|
|
|
|
@ -1,94 +1,111 @@
@@ -1,94 +1,111 @@
|
|
|
|
|
// <file>
|
|
|
|
|
// <copyright see="prj:///doc/copyright.txt"/>
|
|
|
|
|
// <license see="prj:///doc/license.txt"/>
|
|
|
|
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
|
|
|
// <version>$Revision$</version>
|
|
|
|
|
// </file>
|
|
|
|
|
|
|
|
|
|
using System; |
|
|
|
|
using System; |
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using System.Diagnostics; |
|
|
|
|
using System.Linq; |
|
|
|
|
using System.Text; |
|
|
|
|
using System.Windows; |
|
|
|
|
using System.Windows.Controls; |
|
|
|
|
using System.Windows.Data; |
|
|
|
|
using System.Windows.Documents; |
|
|
|
|
using System.Windows.Input; |
|
|
|
|
using System.Windows.Media; |
|
|
|
|
using System.Windows.Media.Imaging; |
|
|
|
|
using System.Windows.Navigation; |
|
|
|
|
using System.Windows.Shapes; |
|
|
|
|
using System.Xml; |
|
|
|
|
|
|
|
|
|
using ICSharpCode.WpfDesign.Designer.Controls; |
|
|
|
|
using ICSharpCode.WpfDesign.Designer.Xaml; |
|
|
|
|
using ICSharpCode.WpfDesign.Designer.Services; |
|
|
|
|
using System.Diagnostics; |
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.WpfDesign.Designer |
|
|
|
|
{ |
|
|
|
|
/// <summary>
|
|
|
|
|
/// Surface hosting the WPF designer.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class DesignSurface : SingleVisualChildElement |
|
|
|
|
public partial class DesignSurface |
|
|
|
|
{ |
|
|
|
|
public static Type[] SupportedToolboxControls = { |
|
|
|
|
typeof(Button), |
|
|
|
|
typeof(CheckBox), |
|
|
|
|
typeof(ComboBox), |
|
|
|
|
typeof(Label), |
|
|
|
|
typeof(TextBox), |
|
|
|
|
typeof(RadioButton), |
|
|
|
|
typeof(Canvas), |
|
|
|
|
typeof(Grid), |
|
|
|
|
typeof(Border), |
|
|
|
|
typeof(DockPanel), |
|
|
|
|
typeof(Expander), |
|
|
|
|
typeof(GroupBox), |
|
|
|
|
typeof(Image), |
|
|
|
|
typeof(InkCanvas), |
|
|
|
|
typeof(ListBox), |
|
|
|
|
typeof(ListView), |
|
|
|
|
typeof(Menu), |
|
|
|
|
typeof(PasswordBox), |
|
|
|
|
typeof(ProgressBar), |
|
|
|
|
typeof(RichTextBox), |
|
|
|
|
typeof(ScrollViewer), |
|
|
|
|
typeof(Slider), |
|
|
|
|
typeof(StackPanel), |
|
|
|
|
typeof(TabControl), |
|
|
|
|
typeof(ToolBar), |
|
|
|
|
typeof(TreeView), |
|
|
|
|
typeof(Viewbox), |
|
|
|
|
typeof(Viewport3D), |
|
|
|
|
typeof(WrapPanel) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
readonly ScrollViewer _scrollViewer; |
|
|
|
|
readonly DesignPanel _designPanel; |
|
|
|
|
public DesignSurface() |
|
|
|
|
{ |
|
|
|
|
InitializeComponent(); |
|
|
|
|
|
|
|
|
|
this.AddCommandHandler(ApplicationCommands.Undo, Undo, CanUndo); |
|
|
|
|
this.AddCommandHandler(ApplicationCommands.Redo, Redo, CanRedo); |
|
|
|
|
this.AddCommandHandler(ApplicationCommands.Copy, Copy, HasSelection); |
|
|
|
|
this.AddCommandHandler(ApplicationCommands.Cut, Cut, HasSelection); |
|
|
|
|
this.AddCommandHandler(ApplicationCommands.Delete, Delete, CanDelete); |
|
|
|
|
this.AddCommandHandler(ApplicationCommands.Paste, Paste, CanPaste); |
|
|
|
|
this.AddCommandHandler(ApplicationCommands.SelectAll, SelectAll, CanSelectAll); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DesignContext _designContext; |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create a new DesignSurface instance.
|
|
|
|
|
/// Gets the active design context.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DesignSurface() |
|
|
|
|
public DesignContext DesignContext { |
|
|
|
|
get { return _designContext; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes the designer content from the specified XmlReader.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void LoadDesigner(XmlReader xamlReader, XamlLoadSettings loadSettings) |
|
|
|
|
{ |
|
|
|
|
UnloadDesigner(); |
|
|
|
|
InitializeDesigner(new XamlDesignContext(xamlReader, loadSettings ?? new XamlLoadSettings())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Saves the designer content into the specified XmlWriter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void SaveDesigner(XmlWriter writer) |
|
|
|
|
{ |
|
|
|
|
_designContext.Save(writer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void InitializeDesigner(DesignContext context) |
|
|
|
|
{ |
|
|
|
|
_scrollViewer = new ScrollViewer(); |
|
|
|
|
_designPanel = new DesignPanel(); |
|
|
|
|
_scrollViewer.Content = _designPanel; |
|
|
|
|
_scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Visible; |
|
|
|
|
_scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible; |
|
|
|
|
context.Services.AddService(typeof(IDesignPanel), _designPanel); |
|
|
|
|
|
|
|
|
|
this.VisualChild = _scrollViewer; |
|
|
|
|
this.DataContext = null; |
|
|
|
|
_designContext = context; |
|
|
|
|
_designPanel.Context = context; |
|
|
|
|
_sceneContainer.Child = context.RootItem.View; |
|
|
|
|
|
|
|
|
|
context.Services.RunWhenAvailable<UndoService>( |
|
|
|
|
undoService => undoService.UndoStackChanged += delegate { |
|
|
|
|
CommandManager.InvalidateRequerySuggested(); |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
context.Services.Selection.SelectionChanged += delegate { |
|
|
|
|
CommandManager.InvalidateRequerySuggested(); |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, OnUndoExecuted, OnUndoCanExecute)); |
|
|
|
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, OnRedoExecuted, OnRedoCanExecute)); |
|
|
|
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDeleteExecuted, OnDeleteCanExecute)); |
|
|
|
|
/// <summary>
|
|
|
|
|
/// Unloads the designer content.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void UnloadDesigner() |
|
|
|
|
{ |
|
|
|
|
if (_designContext != null) { |
|
|
|
|
foreach (object o in _designContext.Services.AllServices) { |
|
|
|
|
IDisposable d = o as IDisposable; |
|
|
|
|
if (d != null) d.Dispose(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_designContext = null; |
|
|
|
|
_designPanel.Context = null; |
|
|
|
|
_sceneContainer.Child = null; |
|
|
|
|
_designPanel.Adorners.Clear(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T GetService<T>() where T : class |
|
|
|
|
#region Commands
|
|
|
|
|
|
|
|
|
|
public bool CanUndo() |
|
|
|
|
{ |
|
|
|
|
if (_designContext != null) |
|
|
|
|
return _designContext.Services.GetService<T>(); |
|
|
|
|
else |
|
|
|
|
return null; |
|
|
|
|
UndoService undoService = GetService<UndoService>(); |
|
|
|
|
return undoService != null && undoService.CanUndo; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#region Command: Undo/Redo
|
|
|
|
|
void OnUndoExecuted(object sender, ExecutedRoutedEventArgs e) |
|
|
|
|
public void Undo() |
|
|
|
|
{ |
|
|
|
|
UndoService undoService = GetService<UndoService>(); |
|
|
|
|
IUndoAction action = undoService.UndoActions.First(); |
|
|
|
|
@ -97,13 +114,13 @@ namespace ICSharpCode.WpfDesign.Designer
@@ -97,13 +114,13 @@ namespace ICSharpCode.WpfDesign.Designer
|
|
|
|
|
_designContext.Services.Selection.SetSelectedComponents(GetLiveElements(action.AffectedElements)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OnUndoCanExecute(object sender, CanExecuteRoutedEventArgs e) |
|
|
|
|
public bool CanRedo() |
|
|
|
|
{ |
|
|
|
|
UndoService undoService = GetService<UndoService>(); |
|
|
|
|
e.CanExecute = undoService != null && undoService.CanUndo; |
|
|
|
|
return undoService != null && undoService.CanRedo; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OnRedoExecuted(object sender, ExecutedRoutedEventArgs e) |
|
|
|
|
public void Redo() |
|
|
|
|
{ |
|
|
|
|
UndoService undoService = GetService<UndoService>(); |
|
|
|
|
IUndoAction action = undoService.RedoActions.First(); |
|
|
|
|
@ -112,103 +129,105 @@ namespace ICSharpCode.WpfDesign.Designer
@@ -112,103 +129,105 @@ namespace ICSharpCode.WpfDesign.Designer
|
|
|
|
|
_designContext.Services.Selection.SetSelectedComponents(GetLiveElements(action.AffectedElements)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OnRedoCanExecute(object sender, CanExecuteRoutedEventArgs e) |
|
|
|
|
public bool HasSelection() |
|
|
|
|
{ |
|
|
|
|
UndoService undoService = GetService<UndoService>(); |
|
|
|
|
e.CanExecute = undoService != null && undoService.CanRedo; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Filters an element list, dropping all elements that are not part of the xaml document
|
|
|
|
|
// (e.g. because they were deleted).
|
|
|
|
|
static List<DesignItem> GetLiveElements(ICollection<DesignItem> items) |
|
|
|
|
public void Copy() |
|
|
|
|
{ |
|
|
|
|
List<DesignItem> result = new List<DesignItem>(items.Count); |
|
|
|
|
foreach (DesignItem item in items) { |
|
|
|
|
if (ModelTools.IsInDocument(item) && ModelTools.CanSelectComponent(item)) { |
|
|
|
|
result.Add(item); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Command: Delete
|
|
|
|
|
void OnDeleteExecuted(object sender, ExecutedRoutedEventArgs e) |
|
|
|
|
public void Cut() |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool CanDelete() |
|
|
|
|
{ |
|
|
|
|
if (_designContext != null) { |
|
|
|
|
ModelTools.DeleteComponents(_designContext.Services.Selection.SelectedItems); |
|
|
|
|
return ModelTools.CanDeleteComponents(_designContext.Services.Selection.SelectedItems); |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OnDeleteCanExecute(object sender, CanExecuteRoutedEventArgs e) |
|
|
|
|
public void Delete() |
|
|
|
|
{ |
|
|
|
|
if (_designContext != null) { |
|
|
|
|
e.CanExecute = ModelTools.CanDeleteComponents(_designContext.Services.Selection.SelectedItems); |
|
|
|
|
} else { |
|
|
|
|
e.CanExecute = false; |
|
|
|
|
ModelTools.DeleteComponents(_designContext.Services.Selection.SelectedItems); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the active design context.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DesignContext DesignContext { |
|
|
|
|
get { return _designContext; } |
|
|
|
|
public bool CanPaste() |
|
|
|
|
{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes the designer content from the specified XmlReader.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void LoadDesigner(XmlReader xamlReader, Xaml.XamlLoadSettings loadSettings) |
|
|
|
|
public void Paste() |
|
|
|
|
{ |
|
|
|
|
UnloadDesigner(); |
|
|
|
|
InitializeDesigner(new Xaml.XamlDesignContext(xamlReader, loadSettings ?? new Xaml.XamlLoadSettings())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Saves the designer content into the specified XmlWriter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void SaveDesigner(XmlWriter writer) |
|
|
|
|
public bool CanSelectAll() |
|
|
|
|
{ |
|
|
|
|
_designContext.Save(writer); |
|
|
|
|
return DesignContext != null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void InitializeDesigner(DesignContext context) |
|
|
|
|
//TODO: Do not select layout root
|
|
|
|
|
public void SelectAll() |
|
|
|
|
{ |
|
|
|
|
context.Services.AddService(typeof(IDesignPanel), _designPanel); |
|
|
|
|
var items = Descendants(DesignContext.RootItem).Where(item => ModelTools.CanSelectComponent(item)).ToArray(); |
|
|
|
|
DesignContext.Services.Selection.SetSelectedComponents(items); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_designContext = context; |
|
|
|
|
_designPanel.Context = context; |
|
|
|
|
Border designPanelBorder = new Border(); |
|
|
|
|
designPanelBorder.Padding = new Thickness(10); |
|
|
|
|
_designPanel.Child = designPanelBorder; |
|
|
|
|
designPanelBorder.Child = context.RootItem.View; |
|
|
|
|
context.Services.RunWhenAvailable<UndoService>( |
|
|
|
|
undoService => undoService.UndoStackChanged += delegate { |
|
|
|
|
CommandManager.InvalidateRequerySuggested(); |
|
|
|
|
//TODO: Share with Outline / PlacementBehavior
|
|
|
|
|
public static IEnumerable<DesignItem> DescendantsAndSelf(DesignItem item) |
|
|
|
|
{ |
|
|
|
|
yield return item; |
|
|
|
|
foreach (var child in Descendants(item)) { |
|
|
|
|
yield return child; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static IEnumerable<DesignItem> Descendants(DesignItem item) |
|
|
|
|
{ |
|
|
|
|
if (item.ContentPropertyName != null) { |
|
|
|
|
var content = item.ContentProperty; |
|
|
|
|
if (content.IsCollection) { |
|
|
|
|
foreach (var child in content.CollectionElements) { |
|
|
|
|
foreach (var child2 in DescendantsAndSelf(child)) { |
|
|
|
|
yield return child2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (content.Value != null) { |
|
|
|
|
foreach (var child2 in DescendantsAndSelf(content.Value)) { |
|
|
|
|
yield return child2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
context.Services.Selection.SelectionChanged += delegate { |
|
|
|
|
CommandManager.InvalidateRequerySuggested(); |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Unloads the designer content.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void UnloadDesigner() |
|
|
|
|
// Filters an element list, dropping all elements that are not part of the xaml document
|
|
|
|
|
// (e.g. because they were deleted).
|
|
|
|
|
static List<DesignItem> GetLiveElements(ICollection<DesignItem> items) |
|
|
|
|
{ |
|
|
|
|
if (_designContext != null) { |
|
|
|
|
foreach (object o in _designContext.Services.AllServices) { |
|
|
|
|
IDisposable d = o as IDisposable; |
|
|
|
|
if (d != null) d.Dispose(); |
|
|
|
|
List<DesignItem> result = new List<DesignItem>(items.Count); |
|
|
|
|
foreach (DesignItem item in items) { |
|
|
|
|
if (ModelTools.IsInDocument(item) && ModelTools.CanSelectComponent(item)) { |
|
|
|
|
result.Add(item); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_designContext = null; |
|
|
|
|
_designPanel.Context = null; |
|
|
|
|
_designPanel.Child = null; |
|
|
|
|
_designPanel.Adorners.Clear(); |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T GetService<T>() where T : class |
|
|
|
|
{ |
|
|
|
|
if (_designContext != null) |
|
|
|
|
return _designContext.Services.GetService<T>(); |
|
|
|
|
else |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
} |
|
|
|
|
} |