Browse Source

Add Undo/Redo support to WpfDesigner.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2410 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
f4e60aae54
  1. BIN
      src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Images/Redo.png
  2. BIN
      src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Images/Undo.png
  3. 3
      src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/StandaloneDesigner.csproj
  4. 6
      src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml
  5. 7
      src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml.cs
  6. 51
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs
  7. 15
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/DefaultChildResizeSupport.cs
  8. 3
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/ResizeThumbExtension.cs
  9. 53
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/UndoService.cs
  10. 116
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlModelProperty.cs
  11. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TextBoxEditor.cs

BIN
src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Images/Redo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

BIN
src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Images/Undo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

3
src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/StandaloneDesigner.csproj

@ -61,5 +61,8 @@
<Project>{66A378A1-E9F4-4AD5-8946-D0EC06C2902F}</Project> <Project>{66A378A1-E9F4-4AD5-8946-D0EC06C2902F}</Project>
<Name>WpfDesign</Name> <Name>WpfDesign</Name>
</ProjectReference> </ProjectReference>
<Folder Include="Images" />
<Resource Include="Images\Redo.png" />
<Resource Include="Images\Undo.png" />
</ItemGroup> </ItemGroup>
</Project> </Project>

6
src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml

@ -4,6 +4,11 @@
xmlns:designer="clr-namespace:ICSharpCode.WpfDesign.Designer;assembly=ICSharpCode.WpfDesign.Designer" xmlns:designer="clr-namespace:ICSharpCode.WpfDesign.Designer;assembly=ICSharpCode.WpfDesign.Designer"
Title="StandaloneDesigner" Height="500" Width="700" Title="StandaloneDesigner" Height="500" Width="700"
> >
<DockPanel>
<ToolBar DockPanel.Dock="Top" Name="toolBar">
<Button Command="Undo"><Image Source="Images/Undo.png" Stretch="None"/></Button>
<Button Command="Redo"><Image Source="Images/Redo.png" Stretch="None"/></Button>
</ToolBar>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
@ -40,4 +45,5 @@
<GridSplitter HorizontalAlignment="Left" Width="4" VerticalAlignment="Stretch" Grid.Column="1"/> <GridSplitter HorizontalAlignment="Left" Width="4" VerticalAlignment="Stretch" Grid.Column="1"/>
<designer:PropertyEditor Name="propertyEditor" Grid.Column="1" Margin="4 0 0 0" FontSize="8.25pt"/> <designer:PropertyEditor Name="propertyEditor" Grid.Column="1" Margin="4 0 0 0" FontSize="8.25pt"/>
</Grid> </Grid>
</DockPanel>
</Window> </Window>

7
src/AddIns/DisplayBindings/WpfDesign/StandaloneDesigner/Window1.xaml.cs

@ -4,6 +4,7 @@ using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup; using System.Windows.Markup;
using System.Xml; using System.Xml;
using ICSharpCode.WpfDesign; using ICSharpCode.WpfDesign;
@ -21,6 +22,11 @@ namespace StandaloneDesigner
{ {
try { try {
InitializeComponent(); InitializeComponent();
foreach (object o in toolBar.Items) {
if (o is Button) {
(o as Button).CommandTarget = designSurface;
}
}
} catch (Exception ex) { } catch (Exception ex) {
MessageBox.Show(ex.ToString()); MessageBox.Show(ex.ToString());
Close(); Close();
@ -32,6 +38,7 @@ namespace StandaloneDesigner
TextBox CodeTextBox; TextBox CodeTextBox;
DesignSurface designSurface; DesignSurface designSurface;
PropertyEditor propertyEditor; PropertyEditor propertyEditor;
ToolBar toolBar;
#endif #endif
void tabControlSelectionChanged(object sender, RoutedEventArgs e) void tabControlSelectionChanged(object sender, RoutedEventArgs e)

51
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs

@ -6,11 +6,14 @@
// </file> // </file>
using System; using System;
using System.Diagnostics;
using System.Windows; using System.Windows;
using System.Windows.Input;
using System.Windows.Controls; using System.Windows.Controls;
using System.Xml; using System.Xml;
using ICSharpCode.WpfDesign.Designer.Controls; using ICSharpCode.WpfDesign.Designer.Controls;
using ICSharpCode.WpfDesign.Designer.Services;
namespace ICSharpCode.WpfDesign.Designer namespace ICSharpCode.WpfDesign.Designer
{ {
@ -34,7 +37,53 @@ namespace ICSharpCode.WpfDesign.Designer
_scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Visible; _scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
_scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible; _scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
this.VisualChild = _scrollViewer; this.VisualChild = _scrollViewer;
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, OnUndoExecuted, OnUndoCanExecute));
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, OnRedoExecuted, OnRedoCanExecute));
}
#region Undo/Redo
UndoService _undoService;
private UndoService UndoService {
get { return _undoService; }
set {
if (_undoService != null) {
_undoService.UndoStackChanged -= OnUndoStackChanged;
}
_undoService = value;
if (_undoService != null) {
_undoService.UndoStackChanged += OnUndoStackChanged;
}
CommandManager.InvalidateRequerySuggested();
}
}
void OnUndoExecuted(object sender, ExecutedRoutedEventArgs e)
{
_undoService.Undo();
}
void OnUndoCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = _undoService != null && _undoService.CanUndo;
}
void OnRedoExecuted(object sender, ExecutedRoutedEventArgs e)
{
_undoService.Redo();
}
void OnRedoCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = _undoService != null && _undoService.CanRedo;
}
void OnUndoStackChanged(object sender, EventArgs e)
{
CommandManager.InvalidateRequerySuggested();
} }
#endregion
/// <summary> /// <summary>
/// Gets the active design context. /// Gets the active design context.
@ -70,6 +119,7 @@ namespace ICSharpCode.WpfDesign.Designer
designPanelBorder.Padding = new Thickness(10); designPanelBorder.Padding = new Thickness(10);
_designPanel.Child = designPanelBorder; _designPanel.Child = designPanelBorder;
designPanelBorder.Child = context.RootItem.View; designPanelBorder.Child = context.RootItem.View;
UndoService = context.Services.GetService<UndoService>();
} }
/// <summary> /// <summary>
@ -82,6 +132,7 @@ namespace ICSharpCode.WpfDesign.Designer
_designPanel.Child = null; _designPanel.Child = null;
_designPanel.Adorners.Clear(); _designPanel.Adorners.Clear();
_designPanel.MarkerCanvas.Children.Clear(); _designPanel.MarkerCanvas.Children.Clear();
UndoService = null;
} }
} }
} }

15
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/DefaultChildResizeSupport.cs

@ -66,10 +66,10 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
public void Resize(DesignItem childItem, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical) public void Resize(DesignItem childItem, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical)
{ {
RelativePlacement p = (RelativePlacement)GetPlacement(childItem, horizontalChange, verticalChange, horizontal, vertical); RelativePlacement p = (RelativePlacement)GetPlacement(childItem, horizontalChange, verticalChange, horizontal, vertical);
Resize(childItem, p, horizontalChange, verticalChange, horizontal, vertical); Resize(childItem, p, horizontal, vertical);
} }
static void Resize(DesignItem childItem, RelativePlacement p, double horizontalChange, double verticalChange, HorizontalAlignment horizontal, VerticalAlignment vertical) static void Resize(DesignItem childItem, RelativePlacement p, HorizontalAlignment horizontal, VerticalAlignment vertical)
{ {
DesignItemProperty margin = childItem.Properties[FrameworkElement.MarginProperty]; DesignItemProperty margin = childItem.Properties[FrameworkElement.MarginProperty];
if (margin.IsSet) { if (margin.IsSet) {
@ -81,6 +81,9 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
margin.SetValue(t); margin.SetValue(t);
} }
double horizontalChange = p.WidthOffset;
double verticalChange = p.HeightOffset;
FrameworkElement child = (FrameworkElement)childItem.Component; FrameworkElement child = (FrameworkElement)childItem.Component;
double width = child.Width; double width = child.Width;
double height = child.Height; double height = child.Height;
@ -130,8 +133,8 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
rp.XOffset -= horizontalChange; rp.XOffset -= horizontalChange;
rp.WidthOffset += horizontalChange; rp.WidthOffset += horizontalChange;
} else { } else {
rp.XOffset -= horizontalChange / 2; rp.XOffset -= horizontalChange;
rp.WidthOffset += horizontalChange; rp.WidthOffset += horizontalChange * 2;
} }
if (vertical == VerticalAlignment.Bottom) { if (vertical == VerticalAlignment.Bottom) {
@ -140,8 +143,8 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
rp.YOffset -= verticalChange; rp.YOffset -= verticalChange;
rp.HeightOffset += verticalChange; rp.HeightOffset += verticalChange;
} else { } else {
rp.YOffset -= verticalChange / 2; rp.YOffset -= verticalChange;
rp.HeightOffset += verticalChange; rp.HeightOffset += verticalChange * 2;
} }
return rp; return rp;

3
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/ResizeThumbExtension.cs

@ -85,10 +85,13 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
adornerPanel.ClearValue(AdornerPanel.CursorProperty); adornerPanel.ClearValue(AdornerPanel.CursorProperty);
if (resizeBehavior != null) { if (resizeBehavior != null) {
using (ChangeGroup group = this.ExtendedItem.OpenGroup("Resize")) {
resizeBehavior.Resize(this.ExtendedItem, resizeBehavior.Resize(this.ExtendedItem,
FixChange(e.HorizontalChange, horizontalAlignment), FixChange(e.HorizontalChange, horizontalAlignment),
FixChange(e.VerticalChange, verticalAlignment), FixChange(e.VerticalChange, verticalAlignment),
horizontalAlignment, verticalAlignment); horizontalAlignment, verticalAlignment);
group.Commit();
}
} }
}; };
} }

53
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/UndoService.cs

@ -17,7 +17,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
void Do(); void Do();
void Undo(); void Undo();
string Title { get; set; } string Title { get; }
} }
#endregion #endregion
@ -100,9 +100,10 @@ namespace ICSharpCode.WpfDesign.Designer.Services
{ {
AssertState(TransactionState.Undone); AssertState(TransactionState.Undone);
try { try {
for (int i = 0; i < items.Count; i--) { for (int i = 0; i < items.Count; i++) {
items[i].Do(); items[i].Do();
} }
_state = TransactionState.Completed;
} catch { } catch {
_state = TransactionState.Failed; _state = TransactionState.Failed;
try { try {
@ -144,18 +145,10 @@ namespace ICSharpCode.WpfDesign.Designer.Services
Stack<ITransactionItem> _undoStack = new Stack<ITransactionItem>(); Stack<ITransactionItem> _undoStack = new Stack<ITransactionItem>();
Stack<ITransactionItem> _redoStack = new Stack<ITransactionItem>(); Stack<ITransactionItem> _redoStack = new Stack<ITransactionItem>();
UndoTransaction CurrentTransaction {
get {
if (_transactionStack.Count == 0)
return null;
else
return _transactionStack.Peek();
}
}
internal UndoTransaction StartTransaction() internal UndoTransaction StartTransaction()
{ {
UndoTransaction t = new UndoTransaction(); UndoTransaction t = new UndoTransaction();
_transactionStack.Push(t);
t.Committed += TransactionFinished; t.Committed += TransactionFinished;
t.RolledBack += TransactionFinished; t.RolledBack += TransactionFinished;
t.Committed += delegate(object sender, EventArgs e) { t.Committed += delegate(object sender, EventArgs e) {
@ -177,6 +170,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
item.Do(); item.Do();
_undoStack.Push(item); _undoStack.Push(item);
_redoStack.Clear(); _redoStack.Clear();
OnUndoStackChanged(EventArgs.Empty);
} else { } else {
_transactionStack.Peek().Execute(item); _transactionStack.Peek().Execute(item);
} }
@ -189,6 +183,18 @@ namespace ICSharpCode.WpfDesign.Designer.Services
get { return _undoStack.Count > 0; } get { return _undoStack.Count > 0; }
} }
/// <summary>
/// Is raised when the undo stack has changed.
/// </summary>
public event EventHandler UndoStackChanged;
void OnUndoStackChanged(EventArgs e)
{
if (UndoStackChanged != null) {
UndoStackChanged(this, e);
}
}
/// <summary> /// <summary>
/// Undoes the last action. /// Undoes the last action.
/// </summary> /// </summary>
@ -202,6 +208,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
try { try {
item.Undo(); item.Undo();
_redoStack.Push(item); _redoStack.Push(item);
OnUndoStackChanged(EventArgs.Empty);
} catch { } catch {
// state might be invalid now, clear stacks to prevent getting more inconsistencies // state might be invalid now, clear stacks to prevent getting more inconsistencies
Clear(); Clear();
@ -209,6 +216,28 @@ namespace ICSharpCode.WpfDesign.Designer.Services
} }
} }
/// <summary>
/// Gets the list of names of the available actions on the undo stack.
/// </summary>
public IEnumerable<string> UndoActions {
get {
foreach (ITransactionItem item in _undoStack) {
yield return item.Title;
}
}
}
/// <summary>
/// Gets the list of names of the available actions on the undo stack.
/// </summary>
public IEnumerable<string> RedoActions {
get {
foreach (ITransactionItem item in _redoStack) {
yield return item.Title;
}
}
}
/// <summary> /// <summary>
/// Gets if there are redo actions available. /// Gets if there are redo actions available.
/// </summary> /// </summary>
@ -227,6 +256,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
try { try {
item.Do(); item.Do();
_undoStack.Push(item); _undoStack.Push(item);
OnUndoStackChanged(EventArgs.Empty);
} catch { } catch {
// state might be invalid now, clear stacks to prevent getting more inconsistencies // state might be invalid now, clear stacks to prevent getting more inconsistencies
Clear(); Clear();
@ -241,6 +271,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
{ {
_undoStack.Clear(); _undoStack.Clear();
_redoStack.Clear(); _redoStack.Clear();
OnUndoStackChanged(EventArgs.Empty);
} }
} }
#endregion #endregion

116
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlModelProperty.cs

@ -11,6 +11,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.WpfDesign.XamlDom; using ICSharpCode.WpfDesign.XamlDom;
using ICSharpCode.WpfDesign.Designer.Services;
namespace ICSharpCode.WpfDesign.Designer.Xaml namespace ICSharpCode.WpfDesign.Designer.Xaml
{ {
@ -88,42 +89,28 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
} }
} }
#if EventHandlerDebugging // There may be multipley XamlModelProperty instances for the same property,
private event EventHandler _ValueChanged; // so this class may not have any mutable fields / events - instead,
// we forward all event handlers to the XamlProperty.
public override event EventHandler ValueChanged { public override event EventHandler ValueChanged {
add { add {
#if EventHandlerDebugging
if (ValueChangedEventHandlers == 0) { if (ValueChangedEventHandlers == 0) {
Debug.WriteLine("ValueChangedEventHandlers is now > 0"); Debug.WriteLine("ValueChangedEventHandlers is now > 0");
} }
ValueChangedEventHandlers++; ValueChangedEventHandlers++;
_ValueChanged += value; #endif
_property.ValueChanged += value;
} }
remove { remove {
#if EventHandlerDebugging
ValueChangedEventHandlers--; ValueChangedEventHandlers--;
if (ValueChangedEventHandlers == 0) { if (ValueChangedEventHandlers == 0) {
Debug.WriteLine("ValueChangedEventHandlers reached 0"); Debug.WriteLine("ValueChangedEventHandlers reached 0");
} }
_ValueChanged -= value;
}
}
#else
public override event EventHandler ValueChanged;
#endif #endif
_property.ValueChanged -= value;
void OnValueChanged(EventArgs e)
{
#if EventHandlerDebugging
if (_ValueChanged != null) {
_ValueChanged(this, EventArgs.Empty);
} }
#else
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
#endif
_designItem.NotifyPropertyChanged(this.Name);
} }
public override object ValueOnInstance { public override object ValueOnInstance {
@ -162,10 +149,9 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
public override void SetValue(object value) public override void SetValue(object value)
{ {
_property.ValueOnInstance = value; XamlPropertyValue newValue;
if (value == null) { if (value == null) {
_property.PropertyValue = _property.ParentObject.OwnerDocument.CreateNullValue(); newValue = _property.ParentObject.OwnerDocument.CreateNullValue();
} else { } else {
XamlComponentService componentService = _designItem.ComponentService; XamlComponentService componentService = _designItem.ComponentService;
@ -173,22 +159,94 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
if (designItem != null) { if (designItem != null) {
if (designItem.Parent != null) if (designItem.Parent != null)
throw new DesignerException("Cannot set value to design item that already has a parent"); throw new DesignerException("Cannot set value to design item that already has a parent");
_property.PropertyValue = designItem.XamlObject; newValue = designItem.XamlObject;
} else { } else {
XamlPropertyValue val = _property.ParentObject.OwnerDocument.CreatePropertyValue(value, _property); XamlPropertyValue val = _property.ParentObject.OwnerDocument.CreatePropertyValue(value, _property);
designItem = componentService.RegisterXamlComponentRecursive(val as XamlObject); designItem = componentService.RegisterXamlComponentRecursive(val as XamlObject);
_property.PropertyValue = val; newValue = val;
} }
} }
OnValueChanged(EventArgs.Empty); UndoService undoService = _designItem.Services.GetService<UndoService>();
if (undoService != null)
undoService.Execute(new PropertyChangeAction(this, true, newValue, value));
else
SetValueInternal(value, newValue);
}
void SetValueInternal(object value, XamlPropertyValue newValue)
{
_property.ValueOnInstance = value;
_property.PropertyValue = newValue;
_designItem.NotifyPropertyChanged(this.Name);
} }
public override void Reset() public override void Reset()
{
UndoService undoService = _designItem.Services.GetService<UndoService>();
if (undoService != null)
undoService.Execute(new PropertyChangeAction(this, false, null, null));
else
ResetInternal();
}
void ResetInternal()
{ {
if (_property.IsSet) { if (_property.IsSet) {
_property.Reset(); _property.Reset();
OnValueChanged(EventArgs.Empty); _designItem.NotifyPropertyChanged(this.Name);
}
}
sealed class PropertyChangeAction : ITransactionItem
{
XamlModelProperty property;
bool newIsSet;
XamlPropertyValue newValue;
object newObject;
XamlPropertyValue oldValue;
object oldObject;
bool oldIsSet;
public PropertyChangeAction(XamlModelProperty property, bool newIsSet, XamlPropertyValue newValue, object newObject)
{
this.property = property;
this.newIsSet = newIsSet;
this.newValue = newValue;
this.newObject = newObject;
oldIsSet = property._property.IsSet;
oldValue = property._property.PropertyValue;
oldObject = property._property.ValueOnInstance;
}
public string Title {
get {
if (newIsSet)
return "Set " + property.Name;
else
return "Reset " + property.Name;
}
}
public void Do()
{
if (newIsSet)
property.SetValueInternal(newObject, newValue);
else
property.ResetInternal();
}
public void Undo()
{
if (oldIsSet)
property.SetValueInternal(oldObject, oldValue);
else
property.ResetInternal();
} }
} }
} }

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TextBoxEditor.cs

@ -35,7 +35,9 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
{ {
this.property = property; this.property = property;
UpdateFromSource(); UpdateFromSource();
PropertyEditorBindingHelper.AddValueChangedEventHandler(this, property, delegate { UpdateFromSource(); }); PropertyEditorBindingHelper.AddValueChangedEventHandler(
this, property, delegate { UpdateFromSource(); }
);
} }
void UpdateFromSource() void UpdateFromSource()

Loading…
Cancel
Save