Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Tool Development 07 - Undo & Redo, Drag & Drop

2,351 views

Published on

Chapter 07 of the lecture Tool Development taught at SAE Institute Hamburg.

Introduction to undo-redo stacks and drag & drop in WPF.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Tool Development 07 - Undo & Redo, Drag & Drop

  1. 1. Tool Development Chapter 07: Undo & Redo, Drag & Drop Nick Prühs
  2. 2. Assignment Solution #6 DEMO 2 / 58
  3. 3. Objectives • To understand how to implement an undo/redo stack • To learn how to properly add drag & drop to your WPF application 3 / 58
  4. 4. Undo Sample Application • Data • List of To-do items • Operations • Add new To-do item • Undo • Redo 4 / 58
  5. 5. TodoItem Class C# 5 / 58 public class TodoItem { public string ItemName { get; set; } public TodoItem(string itemName) { this.ItemName = itemName; } }
  6. 6. MainWindow Markup XAML 6 / 58 <Window x:Class="UndoDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <StackPanel> <ListBox ItemsSource="{Binding Items}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding ItemName}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <DockPanel> <Button DockPanel.Dock="Right" Width="100" Click="OnRedo">Redo</Button> <Button DockPanel.Dock="Right" Width="100" Click="OnUndo">Undo</Button> <Button DockPanel.Dock="Right" Width="100" Click="OnAdd">Add</Button> <TextBox DockPanel.Dock="Left" Name="TextBox"></TextBox> </DockPanel> </StackPanel> </Window>
  7. 7. MainWindow Class C# 7 / 58 private ObservableCollection<TodoItem> items = new ObservableCollection<TodoItem>(); public ObservableCollection<TodoItem> Items { get { return this.items; } } public MainWindow() { InitializeComponent(); DataContext = this; } private void OnAdd(object sender, RoutedEventArgs e) { string itemName = this.TextBox.Text; this.items.Add(new TodoItem(itemName)); }
  8. 8. Design Patterns • General reusable solution to a commonly occurring problem within a given context • Formalized best practices that the programmer must implement themselves in the application • Not a finished design that can be transformed directly into source code • Gained popularity in computer science after the book Design Patterns: Elements of Reusable Object- Oriented Software was published in 1994 by the so- called "Gang of Four" (Gamma et al.) 8 / 78
  9. 9. Advantages of Design Patterns • Speed up the development process by providing tested, proven development paradigms • Improve code readability for coders and architects who are familiar with the patterns 9 / 78
  10. 10. Design Pattern Types • Creational (object creation) • Structural (relationships between objects) • Behavioral (communication between objects) • Concurrency (multi-threaded programming) 10 / 78
  11. 11. Object-Oriented Design 101 • Aggregation • Combine simple objects or data types into more complex ones • Usually expressed by means of references from one object to another • Inheritance • Adding detail to a general data type to create a more specific data type 11 / 78
  12. 12. Object-Oriented Design 101 • Delegation • Handing a task over to another part of the program • Polymorphism • Ad hoc polymorphism (function overloading) • Parametric polymorphism (generic programming) • Subtyping (subclassing) 12 / 78
  13. 13. Object-Oriented Design 101 • Cohesion • Degree to which the elements of a module belong together • How much functionalities embedded in a class have in common • Coupling • Degree to which each program module relies on the other modules 13 / 78
  14. 14. Object-Oriented Design 101 • Cohesion • Degree to which the elements of a module belong together • How much functionalities embedded in a class have in common • Coupling • Degree to which each program module relies on the other modules 14 / 78
  15. 15. Behavioral Design Patterns Communication Between Objects: • Iterator • Observer • Command • Memento • Strategy 15 / 78
  16. 16. Memento Pattern Provides the ability to restore an object to its previous state. 16 / 78 Examples: • Undo
  17. 17. Memento Pattern Provides the ability to restore an object to its previous state. 17 / 78
  18. 18. Memento Class C# 18 / 58 public class Memento { public ObservableCollection<TodoItem> Items { get; set; } }
  19. 19. MainWindow Class C# 19 / 58 private Stack<Memento> undoStack = new Stack<Memento>(); private Stack<Memento> redoStack = new Stack<Memento>(); private void SaveMemento() { Memento memento = new Memento { Items = new ObservableCollection<TodoItem>(this.items) }; this.undoStack.Push(memento); } private void RestoreFromMemento(Memento memento) { this.items.Clear(); foreach (var item in memento.Items) { this.items.Add(item); } }
  20. 20. MainWindow Class C# 20 / 58 public MainWindow() { InitializeComponent(); DataContext = this; // Add initial (empty) state to undo stack. this.SaveMemento(); } private void OnAdd(object sender, RoutedEventArgs e) { // Add new item. var itemName = this.TextBox.Text; this.items.Add(new TodoItem(itemName)); // Save memento and clear Redo stack. this.SaveMemento(); this.redoStack.Clear(); }
  21. 21. MainWindow Class C# 21 / 58 private void OnUndo(object sender, RoutedEventArgs e) { if (undoStack.Count < 2) { return; } // Move memento from Undo to Redo stack. Memento memento = undoStack.Pop(); redoStack.Push(memento); // Restore previous state. memento = undoStack.Peek(); this.RestoreFromMemento(memento); }
  22. 22. MainWindow Class C# 22 / 58 private void OnRedo(object sender, RoutedEventArgs e) { if (redoStack.Count < 1) { return; } // Move memento from Redo to Undo stack. Memento memento = redoStack.Pop(); undoStack.Push(memento); // Restore previous state. this.RestoreFromMemento(memento); }
  23. 23. Command Pattern Encapsulates all the information needed to call a method at a later time in an object. 23 / 78 Examples: • Networking • Replays • AI • Undo
  24. 24. Command Pattern Encapsulates all the information needed to call a method at a later time in an object. 24 / 78
  25. 25. Command Pattern Encapsulates all the information needed to call a method at a later time in an object. 25 / 78
  26. 26. ICommand Interface C# 26 / 58 public interface ICommand { void DoCommand(); void UndoCommand(); }
  27. 27. AddItemCommand Class C# 27 / 58 public class AddItemCommand : ICommand { private ObservableCollection<TodoItem> items; private string newItemName; public AddItemCommand(ObservableCollection<TodoItem> items, string newItemName) { this.items = items; this.newItemName = newItemName; } public void DoCommand() { TodoItem todoItem = new TodoItem(this.newItemName); this.items.Add(todoItem); } public void UndoCommand() { TodoItem todoItem = this.items.First(item => item.ItemName.Equals(this.newItemName)); this.items.Remove(todoItem); } }
  28. 28. MainWindow Class C# 28 / 58 private Stack<ICommand> undoStack = new Stack<ICommand>(); private Stack<ICommand> redoStack = new Stack<ICommand>(); private void OnAdd(object sender, RoutedEventArgs e) { // Add new item. var itemName = this.TextBox.Text; AddItemCommand command = new AddItemCommand(this.items, itemName); command.DoCommand(); // Save command and clear Redo stack. this.undoStack.Push(command); this.redoStack.Clear(); }
  29. 29. MainWindow Class C# 29 / 58 private void OnUndo(object sender, RoutedEventArgs e) { if (undoStack.Count < 1) { return; } // Move command from Undo to Redo stack. ICommand command = undoStack.Pop(); redoStack.Push(command); // Undo command. command.UndoCommand(); }
  30. 30. MainWindow Class C# 30 / 58 private void OnRedo(object sender, RoutedEventArgs e) { if (redoStack.Count < 1) { return; } // Move command from Redo to Undo stack. ICommand command = redoStack.Pop(); undoStack.Push(command); // Redo command. command.DoCommand(); }
  31. 31. Drag & Drop • Commonly refers to a method of data transfer that involves using a mouse (or some other pointing device) to • select one or more objects, • dragging these objects over some desired drop target in the user interface (UI), • and dropping them. 31 / 58
  32. 32. Drag & Drop in WPF • Drag-and-drop operations typically involve two parties: • drag source from which the dragged object originates • drop target which receives the dropped object • Drag source and drop target may be UI elements in the same application or a different application. 32 / 58
  33. 33. Drag & Drop in WPF • The type and number of objects that can be manipulated with drag-and-drop is completely arbitrary. • Files • Folders • Content • The particular actions performed during a drag- and-drop operation are application-specific, and often determined by context. 33 / 58
  34. 34. Drag & Drop Data Transfer • Dragging and dropping items requires a way to temporarily store the transferred data. • WPF uses a DataObject to store the data: • The drag source initiates a drag-and-drop operation, passing the transferred data to it. • Any serializable object can be passed. If the data is not already wrapped in a DataObject, it will automatically be wrapped in a new DataObject. • For greater control over the data format, you can wrap the data in a DataObject yourself. • The drop target is responsible for extracting the data from the DataObject. 34 / 58
  35. 35. Drag & Drop Effects • Data that is actually being transferred typically does not have a visual representation. • By default, feedback is provided to the user by changing the cursor to represent the effect that the drag-and-drop operation will have on the data, such as whether the data will be moved or copied. • WPF defines a DragDropEffects enumeration that you can use to specify the effect of a drag-and-drop operation. • It is important to remember that in WPF, the actual effect of the drag-and-drop operation depends on you to write the appropriate code in your application. • For example, the drop target might specify that the effect of dropping data on it is to move the data. • However, to move the data, it must be both added to the target element and removed from the source element. 35 / 58
  36. 36. Implementing Drag & Drop 1. Drag Source 1. Identify the element that will be a drag source. A drag source can be a UIElement or a ContentElement. 2. Create an event handler on the drag source that will initiate the drag-and-drop operation. The event is typically the MouseMove event. 3. In the drag source event handler, call the DoDragDrop method to initiate the drag-and-drop operation. In the DoDragDrop call, specify the drag source, the data to be transferred, and the allowed effects. 36 / 58
  37. 37. Implementing Drag & Drop 2. Drop Target 1. Identify the element that will be a drop target. A drop target can be UIElement or a ContentElement. 2. On the drop target, set the AllowDrop property to true. 3. In the drop target, create a Drop event handler to process the dropped data. 4. In the Drop event handler, extract the data from the DragEventArgs by using the GetDataPresent and GetData methods. 5. In the Drop event handler, use the data to perform the desired drag-and-drop operation. 37 / 58
  38. 38. Drag & Drop Sample Application • Data • List of To-do items – Today • List of To-do items – Tomorrow • Operations • Move To-Do item from today to tomorrow 38 / 58
  39. 39. MainWindow Markup XAML 39 / 58 <Window x:Class="DragDropDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="To-Do List" Height="350" Width="300"> <StackPanel Orientation="Horizontal"> <StackPanel> <TextBlock Text="Today" /> <ListBox Width="150" ItemsSource="{Binding Today}" MouseMove="UIElement_OnMouseMove"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding ItemName}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> <StackPanel> <TextBlock Text="Tomorrow" /> <ListBox Width="150" ItemsSource="{Binding Tomorrow}" AllowDrop="True" DragOver="UIElement_OnDragOver" Drop="UIElement_OnDrop"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding ItemName}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> </StackPanel> </Window>
  40. 40. MainWindow Class C# 40 / 58 private ObservableCollection<TodoItem> today = new ObservableCollection<TodoItem>(); private ObservableCollection<TodoItem> tomorrow = new ObservableCollection<TodoItem>(); public ObservableCollection<TodoItem> Today { get { return this.today; } } public ObservableCollection<TodoItem> Tomorrow { get { return this.tomorrow; } } public MainWindow() { InitializeComponent(); DataContext = this; this.today.Add(new TodoItem("Wash the dishes")); this.today.Add(new TodoItem("Clean up the closet")); this.tomorrow.Add(new TodoItem("Buy new pizza")); this.tomorrow.Add(new TodoItem("Prepare next lecture")); }
  41. 41. MainWindow Class C# 41 / 58 private void UIElement_OnMouseMove(object sender, MouseEventArgs e) { ListBox listBox = (ListBox)sender; TodoItem selectedItem = (TodoItem)listBox.SelectedItem; if (e.LeftButton == MouseButtonState.Pressed) { // Prepare data to be transferred. DragDrop.DoDragDrop(listBox, selectedItem.ItemName, DragDropEffects.Move); } }
  42. 42. MainWindow Class C# 42 / 58 private void UIElement_OnDragOver(object sender, DragEventArgs e) { e.Effects = DragDropEffects.None; // Check if any data is present. if (e.Data.GetDataPresent(DataFormats.StringFormat)) { // Check if the data is valid for our to-do list. string dataString = (string)e.Data.GetData(DataFormats.StringFormat); if (this.CheckData(dataString)) { // Change drag & drop effect e.Effects = DragDropEffects.Copy | DragDropEffects.Move; } } }
  43. 43. MainWindow Class C# 43 / 58 private void UIElement_OnDrop(object sender, DragEventArgs e) { ListBox listBox = (ListBox)sender; if (listBox != null) { // Check if any data is present. if (e.Data.GetDataPresent(DataFormats.StringFormat)) { // Check if the data is valid for our to-do list. string dataString = (string)e.Data.GetData(DataFormats.StringFormat); if (this.CheckData(dataString)) { // Move to-do list item from today to tomorrow. TodoItem todoItem = today.First(item => item.ItemName.Equals(dataString)); today.Remove(todoItem); tomorrow.Add(todoItem); } } } }
  44. 44. Enhanced Drag & Drop To transfer custom data or multiple data items, create a DataObject to pass to the DoDragDrop method: string stringData = "Some string data to store..."; string dataFormat = DataFormats.UnicodeText; DataObject dataObject = new DataObject(dataFormat, stringData); 44 / 58
  45. 45. Drag & Drop Data Formats 45 / 58 Field Field Value Description Bitmap "Bitmap" Specifies a Microsoft Windows bitmap data format. CommaSeparatedValue "CSV" Specifies a comma-separated value (CSV) data format. Dib "DeviceIndependentBitmap" Specifies the device-independent bitmap (DIB) data format. Dif "DataInterchangeFormat" Specifies the Windows Data Interchange Format (DIF) data format. EnhancedMetafile "EnhancedMetafile" Specifies the Windows enhanced metafile format. FileDrop "FileDrop" Specifies the Windows file drop format. Html "HTML Format" Specifies the HTML data format. Locale "Locale" Specifies the Windows locale (culture) data format. MetafilePicture "MetaFilePict" Specifies the Windows metafile picture data format. OemText "OEMText" Specifies the standard Windows OEM text data format.
  46. 46. Drag & Drop Data Formats 46 / 58 Field Field Value Description Palette "Palette" Specifies the Windows palette data format. PenData "PenData" Specifies the Windows pen data format. Riff "RiffAudio" Specifies the Resource Interchange File Format (RIFF) audio data format. Rtf "Rich Text Format" Specifies the Rich Text Format (RTF) data format. Serializable "PersistentObject" Specifies a data format that encapsulates any type of serializable data objects. StringFormat "System.String" Specifies the common language runtime (CLR) string class data format. SymbolicLink "SymbolicLink" Specifies the Windows symbolic link data format. Text "Text" Specifies the ANSI text data format. Tiff "TaggedImageFileFormat" Specifies the Tagged Image File Format (TIFF) data format. UnicodeText "UnicodeText" Specifies the Unicode text data format. WaveAudio "WaveAudio" Specifies the wave audio data format. Xaml "Xaml" Specifies the Extensible Application Markup Language (XAML) data format. XamlPackage "XamlPackage" Specifies the Extensible Application Markup Language (XAML) package data format.
  47. 47. Drag & Drop Preview • DragEnter event is raised once each time an object is dragged into the bounds of an element that is acting as a drop target. • Handle this event to provide a preview of the effects of the drag-and-drop operation, if appropriate for your application. • DragLeave event occurs when the data is dragged out of the target's boundary without being dropped. • Handle this event to undo anything that you did in the DragEnter event handler. 47 / 58
  48. 48. Drag & Drop Feedback • GiveFeedback event is raised continuously while the drag source is being dragged. • Handle this event if you need to use custom cursors to provide feedback to the user. • Default handler for this event checks whether the drag source is over a valid drop target. 48 / 58
  49. 49. Cancel Drag & Drop • QueryContinueDrag event is raised continuously while the drag source is being dragged. • Handle this event to determine what action ends the drag-and-drop operation based on the state of the ESC, SHIFT, CTRL, and ALT keys, as well as the state of the mouse buttons. • Default handler for this event cancels the drag-and-drop operation if the ESC key is pressed, and drops the data if the mouse button is released. 49 / 58
  50. 50. Assignment #7 Undo & Redo 1. Add menu items and toolbar buttons for Undo and Redo to your main window. 2. Use the Command pattern to add undo and redo for drawing map tiles to your application. 3. A single undo or redo should affect all map tiles drawn with a single click. 4. Both the undo and redo stacks should be cleared when creating a new map or loading an existing one. 5. Both operations should only be available if the respective stacks are not empty. 50 / 58
  51. 51. References • Paul. Multilevel Undo and Redo Implementation in C#. http://www.codeproject.com/Articles/33384/Multi level-Undo-and-Redo-Implementation-in-C-Part, February 17, 2009. • MSDN. Drag and Drop Overview. https://msdn.microsoft.com/de- de/library/ms742859(v=vs.110).aspx, May 2016. 51 / 58
  52. 52. Thank you! http://www.npruehs.de https://github.com/npruehs @npruehs dev@npruehs.de
  53. 53. 5 Minute Review Session • What are the main advantages of design patterns? • Which types of design patterns do you know? • What’s the difference between inheritance and aggregation? • Which types of polymorphism do you know? • What’s the difference between cohesion and coupling? • Which design patterns can be used for implementing an undo-redo stack? • Which parties are typically involved in drag-and-drop operations? • How do you tell the user about the effect that the drag-and- drop operation will have on the data? 53 / 58

×