+ All Categories
Home > Technology > Tool Development 07 - Undo & Redo, Drag & Drop

Tool Development 07 - Undo & Redo, Drag & Drop

Date post: 03-Sep-2014
Category:
Upload: nick-pruehs
View: 1,269 times
Download: 0 times
Share this document with a friend
Description:
Chapter 07 of the lecture Tool Development taught at SAE Institute Hamburg. Introduction to undo-redo stacks and drag & drop in WPF.
Popular Tags:
53
Tool Development Chapter 07: Undo & Redo, Drag & Drop Nick Prühs June 25, 2014
Transcript
Page 1: Tool Development 07 - Undo & Redo, Drag & Drop

Tool DevelopmentChapter 07: Undo & Redo, Drag & Drop

Nick Prühs

June 25, 2014

Page 2: Tool Development 07 - Undo & Redo, Drag & Drop

5 Minute Review Session

• What are two possible approaches for binary serialization?

• What are the advantages and disadvantages of binary serialization via interfaces?

• What are the advantages and disadvantages of binary serialization via reflection?

• Why and when should you use a Background Worker in your UI?

• How do you work with Background Workers?

• How do you pass data to and from Background Workers?

2 / 58

Page 3: Tool Development 07 - Undo & Redo, Drag & Drop

Assignment Solution #6

DEMO

3 / 58

Page 4: Tool Development 07 - Undo & Redo, Drag & Drop

Objectives

• To understand how to implement an undo/redo stack

• To learn how to properly add drag & drop to your WPF application

4 / 58

Page 5: Tool Development 07 - Undo & Redo, Drag & Drop

Undo Sample Application

• Data• List of To-do items

• Operations• Add new To-do item

• Undo

• Redo

5 / 58

Page 6: Tool Development 07 - Undo & Redo, Drag & Drop

TodoItem Class

C#

6 / 58

public class TodoItem

{

public string ItemName { get; set; }

public TodoItem(string itemName)

{

this.ItemName = itemName;

}

}

Page 7: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Markup

XAML

7 / 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>

Page 8: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

8 / 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));

}

Page 9: Tool Development 07 - Undo & Redo, Drag & Drop

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.)

9 / 78

Page 10: Tool Development 07 - Undo & Redo, Drag & Drop

Advantages ofDesign 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

10 / 78

Page 11: Tool Development 07 - Undo & Redo, Drag & Drop

Design Pattern Types

• Creational (object creation)

• Structural (relationships between objects)

• Behavioral (communication between objects)

• Concurrency (multi-threaded programming)

11 / 78

Page 12: Tool Development 07 - Undo & Redo, Drag & Drop

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

12 / 78

Page 13: Tool Development 07 - Undo & Redo, Drag & Drop

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)

13 / 78

Page 14: Tool Development 07 - Undo & Redo, Drag & Drop

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

Page 15: Tool Development 07 - Undo & Redo, Drag & Drop

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

15 / 78

Page 16: Tool Development 07 - Undo & Redo, Drag & Drop

Behavioral Design Patterns

Communication Between Objects:

• Iterator

• Observer

• Command

• Memento

• Strategy

16 / 78

Page 17: Tool Development 07 - Undo & Redo, Drag & Drop

Memento Pattern

Provides the ability to restore an object to its previous state.

17 / 78

Examples:

• Undo

Page 18: Tool Development 07 - Undo & Redo, Drag & Drop

Memento Pattern

Provides the ability to restore an object to its previous state.

18 / 78

Page 19: Tool Development 07 - Undo & Redo, Drag & Drop

Memento Class

C#

19 / 58

public class Memento

{

public ObservableCollection<TodoItem> Items { get; set; }

}

Page 20: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

20 / 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);

}

}

Page 21: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

21 / 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();

}

Page 22: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

22 / 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);

}

Page 23: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

23 / 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);

}

Page 24: Tool Development 07 - Undo & Redo, Drag & Drop

Command Pattern

Encapsulates all the information needed to call a method at a later time in an object.

24 / 78

Examples:

• Networking• Replays• AI• Undo

Page 25: Tool Development 07 - Undo & Redo, Drag & Drop

Command Pattern

Encapsulates all the information needed to call a method at a later time in an object.

25 / 78

Page 26: Tool Development 07 - Undo & Redo, Drag & Drop

Command Pattern

Encapsulates all the information needed to call a method at a later time in an object.

26 / 78

Page 27: Tool Development 07 - Undo & Redo, Drag & Drop

ICommand Interface

C#

27 / 58

public interface ICommand

{

void DoCommand();

void UndoCommand();

}

Page 28: Tool Development 07 - Undo & Redo, Drag & Drop

AddItemCommand Class

C#

28 / 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);

}}

Page 29: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

29 / 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();

}

Page 30: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

30 / 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();

}

Page 31: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

31 / 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();

}

Page 32: Tool Development 07 - Undo & Redo, Drag & Drop

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.

32 / 58

Page 33: Tool Development 07 - Undo & Redo, Drag & Drop

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.

33 / 58

Page 34: Tool Development 07 - Undo & Redo, Drag & Drop

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.

34 / 58

Page 35: Tool Development 07 - Undo & Redo, Drag & Drop

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.

35 / 58

Page 36: Tool Development 07 - Undo & Redo, Drag & Drop

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.

36 / 58

Page 37: Tool Development 07 - Undo & Redo, Drag & Drop

Implementing Drag & Drop

1. Drop 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.

37 / 58

Page 38: Tool Development 07 - Undo & Redo, Drag & Drop

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.

38 / 58

Page 39: Tool Development 07 - Undo & Redo, Drag & Drop

Drag & DropSample Application• Data

• List of To-do items – Today

• List of To-do items – Tomorrow

• Operations• Move To-Do item from today to tomorrow

39 / 58

Page 40: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Markup

XAML

40 / 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>

Page 41: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

41 / 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"));

}

Page 42: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

42 / 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);

}

}

Page 43: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

43 / 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 effecte.Effects = DragDropEffects.Copy | DragDropEffects.Move;

}}

}

Page 44: Tool Development 07 - Undo & Redo, Drag & Drop

MainWindow Class

C#

44 / 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);

}}

}}

Page 45: Tool Development 07 - Undo & Redo, Drag & Drop

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);

45 / 58

Page 46: Tool Development 07 - Undo & Redo, Drag & Drop

Drag & Drop Data Formats

46 / 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.

Page 47: Tool Development 07 - Undo & Redo, Drag & Drop

Drag & Drop Data Formats

47 / 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.

Page 48: Tool Development 07 - Undo & Redo, Drag & Drop

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.

48 / 58

Page 49: Tool Development 07 - Undo & Redo, Drag & Drop

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.

49 / 58

Page 50: Tool Development 07 - Undo & Redo, Drag & Drop

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.

50 / 58

Page 51: Tool Development 07 - Undo & Redo, Drag & Drop

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.

51 / 58

Page 52: Tool Development 07 - Undo & Redo, Drag & Drop

References

• Paul. Multilevel Undo and Redo Implementation in C#. http://www.codeproject.com/Articles/33384/Multilevel-Undo-and-Redo-Implementation-in-C-Part, February 17, 2009.

• MSDN. Drag and Drop Overview. http://msdn.microsoft.com/en-us/library/ms742859(v=vs.110).aspx, June 2014.

52 / 58

Page 53: Tool Development 07 - Undo & Redo, Drag & Drop

Thank you for your attention!

Contact

Mail

[email protected]

Blog

http://www.npruehs.de

Twitter

@npruehs

Github

https://github.com/npruehs

53 / 58


Recommended