Browse Source

Add adorner support.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2227 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
c44f429646
  1. 191
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/AdornerLayer.cs
  2. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/SingleVisualChildElement.cs
  3. 112
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs
  4. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs
  5. 43
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SelectedElementRectangleExtension.cs
  6. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/SelectionService.cs
  7. 12
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
  8. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
  9. 117
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs
  10. 145
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs
  11. 50
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProviderClasses.cs
  12. 150
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/Placement.cs
  13. 58
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs
  14. 63
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs
  15. 114
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs
  16. 22
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs
  17. 93
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/SelectionExtensionServer.cs
  18. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs
  19. 6
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs
  20. 7
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

191
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/AdornerLayer.cs

@ -0,0 +1,191 @@ @@ -0,0 +1,191 @@
// <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.Diagnostics;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using ICSharpCode.WpfDesign.Adorners;
namespace ICSharpCode.WpfDesign.Designer.Controls
{
/// <summary>
/// A control that displays adorner panels.
/// </summary>
sealed class AdornerLayer : Panel
{
#region AdornerPanelCollection
internal sealed class AdornerPanelCollection : ICollection<AdornerPanel>
{
readonly AdornerLayer _layer;
public AdornerPanelCollection(AdornerLayer layer)
{
this._layer = layer;
}
public int Count {
get { return _layer.Children.Count; }
}
public bool IsReadOnly {
get { return false; }
}
public void Add(AdornerPanel item)
{
if (item == null)
throw new ArgumentNullException("item");
_layer.AddAdorner(item);
}
public void Clear()
{
_layer.ClearAdorners();
}
public bool Contains(AdornerPanel item)
{
if (item == null)
throw new ArgumentNullException("item");
return VisualTreeHelper.GetParent(item) == _layer;
}
public void CopyTo(AdornerPanel[] array, int arrayIndex)
{
Linq.ToArray(this).CopyTo(array, arrayIndex);
}
public bool Remove(AdornerPanel item)
{
if (item == null)
throw new ArgumentNullException("item");
return _layer.RemoveAdorner(item);
}
public IEnumerator<AdornerPanel> GetEnumerator()
{
foreach (AdornerPanel panel in _layer.Children) {
yield return panel;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
#endregion
AdornerPanelCollection _adorners;
readonly UIElement _designPanel;
internal AdornerLayer(UIElement designPanel)
{
this._designPanel = designPanel;
_adorners = new AdornerPanelCollection(this);
ClearAdorners();
}
internal AdornerPanelCollection Adorners {
get {
return _adorners;
}
}
sealed class AdornerInfo
{
internal readonly List<AdornerPanel> adorners = new List<AdornerPanel>();
}
// adorned element => AdornerInfo
Dictionary<UIElement, AdornerInfo> _dict;
void ClearAdorners()
{
this.Children.Clear();
_dict = new Dictionary<UIElement, AdornerInfo>();
}
AdornerInfo GetAdornerInfo(UIElement adornedElement)
{
AdornerInfo info;
if (!_dict.TryGetValue(adornedElement, out info)) {
info = _dict[adornedElement] = new AdornerInfo();
}
return info;
}
AdornerInfo GetExistingAdornerInfo(UIElement adornedElement)
{
AdornerInfo info;
_dict.TryGetValue(adornedElement, out info);
return info;
}
void AddAdorner(AdornerPanel adornerPanel)
{
if (adornerPanel.AdornedElement == null)
throw new DesignerException("adornerPanel.AdornedElement must be set");
GetAdornerInfo(adornerPanel.AdornedElement).adorners.Add(adornerPanel);
UIElementCollection children = this.Children;
int i = 0;
for (i = 0; i < children.Count; i++) {
AdornerPanel p = (AdornerPanel)children[i];
if (p.Order.CompareTo(adornerPanel.Order) > 0) {
break;
}
}
children.Insert(i, adornerPanel);
this.InvalidateMeasure();
}
protected override Size MeasureOverride(Size availableSize)
{
Size infiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
foreach (AdornerPanel adorner in this.Children) {
adorner.Measure(infiniteSize);
}
return new Size(0, 0);
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (AdornerPanel adorner in this.Children) {
adorner.Arrange(new Rect(new Point(0, 0), adorner.DesiredSize));
adorner.RenderTransform = (Transform)adorner.AdornedElement.TransformToAncestor(_designPanel);
}
return finalSize;
}
bool RemoveAdorner(AdornerPanel adornerPanel)
{
if (adornerPanel.AdornedElement == null)
return false;
AdornerInfo info = GetExistingAdornerInfo(adornerPanel.AdornedElement);
if (info == null)
return false;
if (info.adorners.Remove(adornerPanel)) {
this.Children.Remove(adornerPanel);
return true;
} else {
return false;
}
}
}
}

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/SingleVisualChildElement.cs

@ -33,7 +33,7 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -33,7 +33,7 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
}
/// <summary>
/// Gets the visual child the design surfaces uses to display itself.
/// Gets the visual child.
/// </summary>
protected override Visual GetVisualChild(int index)
{
@ -44,7 +44,7 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -44,7 +44,7 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
}
/// <summary>
/// Gets the number of visual children the design surface has.
/// Gets the number of visual children.
/// </summary>
protected override int VisualChildrenCount {
get { return _visualChild != null ? 1 : 0; }

112
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs

@ -11,42 +11,106 @@ using System.Windows; @@ -11,42 +11,106 @@ using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Windows.Threading;
using ICSharpCode.WpfDesign.Designer.Controls;
using ICSharpCode.WpfDesign.Adorners;
namespace ICSharpCode.WpfDesign.Designer
{
sealed class DesignPanel : SingleVisualChildElement, IDesignPanel
sealed class DesignPanel : Decorator, IDesignPanel
{
sealed class InnerDesignPanel : SingleVisualChildElement
/// <summary>
/// this element is always hit (unless HitTestVisible is set to false)
/// </summary>
sealed class EatAllHitTestRequests : UIElement
{
internal void SetElement(UIElement element)
protected override GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters)
{
return new GeometryHitTestResult(this, IntersectionDetail.FullyContains);
}
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
this.VisualChild = element;
return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
}
DesignContext _context;
InnerDesignPanel _innerDesignPanel;
UIElement _designedElement;
EatAllHitTestRequests _eatAllHitTestRequests;
AdornerLayer _adornerLayer;
public DesignPanel()
{
this.Focusable = true;
_eatAllHitTestRequests = new EatAllHitTestRequests();
_eatAllHitTestRequests.IsHitTestVisible = false;
_adornerLayer = new AdornerLayer(this);
}
#region Visual Child Management
public override UIElement Child {
get { return base.Child; }
set {
if (base.Child == value)
return;
if (value == null) {
// Child is being set from some value to null
// remove _adornerLayer and _eatAllHitTestRequests
RemoveVisualChild(_adornerLayer);
RemoveVisualChild(_eatAllHitTestRequests);
} else if (base.Child == null) {
// Child is being set from null to some value
AddVisualChild(_adornerLayer);
AddVisualChild(_eatAllHitTestRequests);
}
base.Child = value;
}
}
_innerDesignPanel = new InnerDesignPanel();
this.VisualChild = _innerDesignPanel;
protected override Visual GetVisualChild(int index)
{
if (base.Child != null) {
if (index == 0)
return base.Child;
else if (index == 1)
return _eatAllHitTestRequests;
else if (index == 2)
return _adornerLayer;
}
return base.GetVisualChild(index);
}
public UIElement DesignedElement {
protected override int VisualChildrenCount {
get {
return _designedElement;
if (base.Child != null)
return 3;
else
return base.VisualChildrenCount;
}
set {
_designedElement = value;
_innerDesignPanel.SetElement(value);
}
protected override Size MeasureOverride(Size constraint)
{
Size result = base.MeasureOverride(constraint);
if (this.Child != null) {
_adornerLayer.Measure(constraint);
_eatAllHitTestRequests.Measure(constraint);
}
return result;
}
protected override Size ArrangeOverride(Size arrangeSize)
{
Size result = base.ArrangeOverride(arrangeSize);
if (this.Child != null) {
_adornerLayer.Arrange(new Rect(new Point(0, 0), arrangeSize));
_eatAllHitTestRequests.Arrange(new Rect(new Point(0, 0), arrangeSize));
}
return result;
}
#endregion
/// <summary>
/// Gets/Sets the design context.
@ -61,16 +125,6 @@ namespace ICSharpCode.WpfDesign.Designer @@ -61,16 +125,6 @@ namespace ICSharpCode.WpfDesign.Designer
get { return _context.Services.Tool; }
}
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
protected override GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters)
{
return new GeometryHitTestResult(this, IntersectionDetail.NotCalculated);
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseDown(e);
@ -98,7 +152,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -98,7 +152,7 @@ namespace ICSharpCode.WpfDesign.Designer
DesignItem site = _context.Services.Component.GetDesignItem(originalSource);
if (site != null)
return site;
if (originalSource == _innerDesignPanel)
if (originalSource == this)
return null;
DependencyObject dObj = originalSource as DependencyObject;
if (dObj == null)
@ -128,14 +182,20 @@ namespace ICSharpCode.WpfDesign.Designer @@ -128,14 +182,20 @@ namespace ICSharpCode.WpfDesign.Designer
{
if (_isInInputAction) throw new InvalidOperationException();
_isInInputAction = true;
_innerDesignPanel.IsHitTestVisible = false;
_eatAllHitTestRequests.IsHitTestVisible = true;
}
void IDesignPanel.StopInputAction()
{
if (!_isInInputAction) throw new InvalidOperationException();
_isInInputAction = false;
_innerDesignPanel.IsHitTestVisible = true;
_eatAllHitTestRequests.IsHitTestVisible = false;
}
public ICollection<AdornerPanel> Adorners {
get {
return _adornerLayer.Adorners;
}
}
}

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

@ -48,7 +48,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -48,7 +48,7 @@ namespace ICSharpCode.WpfDesign.Designer
/// </summary>
public UIElement DesignedElement {
get {
return _designPanel.DesignedElement;
return _designPanel.Child;
}
}
@ -71,9 +71,11 @@ namespace ICSharpCode.WpfDesign.Designer @@ -71,9 +71,11 @@ namespace ICSharpCode.WpfDesign.Designer
void InitializeDesigner(DesignContext context)
{
context.Services.AddService(typeof(IDesignPanel), _designPanel);
_designContext = context;
_designPanel.Context = context;
_designPanel.DesignedElement = context.RootItem.View;
_designPanel.Child = context.RootItem.View;
}
/// <summary>
@ -83,7 +85,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -83,7 +85,7 @@ namespace ICSharpCode.WpfDesign.Designer
{
_designContext = null;
_designPanel.Context = null;
_designPanel.DesignedElement = null;
_designPanel.Child = null;
}
}
}

43
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SelectedElementRectangleExtension.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// <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.Windows.Media;
using System.Windows.Shapes;
using ICSharpCode.WpfDesign.Adorners;
using ICSharpCode.WpfDesign.Extensions;
using ICSharpCode.WpfDesign.Designer.Controls;
using System.Windows;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
/// <summary>
/// Draws a dotted line around selected UIElements.
/// </summary>
[ExtensionFor(typeof(UIElement))]
public class SelectedElementRectangleExtension : SelectionAdornerProvider
{
/// <summary>
/// Creates a new SelectedElementRectangleExtension instance.
/// </summary>
public SelectedElementRectangleExtension()
{
Rectangle r = new Rectangle();
r.SnapsToDevicePixels = true;
r.Stroke = Brushes.Black;
r.StrokeDashCap = PenLineCap.Square;
r.StrokeDashArray = new DoubleCollection(new double[] { 0, 2 });
r.IsHitTestVisible = false;
Placement placement = new Placement();
placement.WidthRelativeToContentWidth = 1;
placement.HeightRelativeToContentHeight = 1;
this.AddAdorner(r, placement);
}
}
}

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/SelectionService.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -46,7 +46,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
public void SetSelectedComponents(ICollection<DesignItem> components)
{
SetSelectedComponents(components, SelectionTypes.Auto);
SetSelectedComponents(components, SelectionTypes.Replace);
}
public void SetSelectedComponents(ICollection<DesignItem> components, SelectionTypes selectionType)

12
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs

@ -10,9 +10,7 @@ using System.Windows.Input; @@ -10,9 +10,7 @@ using System.Windows.Input;
namespace ICSharpCode.WpfDesign.Designer.Services
{
/// <summary>
/// See <see cref="IToolService"/> for description.
/// </summary>
// See IToolService for description.
sealed class DefaultToolService : IToolService
{
PointerTool _pointerTool;
@ -57,11 +55,13 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -57,11 +55,13 @@ namespace ICSharpCode.WpfDesign.Designer.Services
abstract class MouseGestureBase
{
protected IDesignPanel designPanel;
protected ServiceContainer services;
bool isStarted;
public void Start(IDesignPanel designPanel, MouseButtonEventArgs e)
{
this.designPanel = designPanel;
this.services = designPanel.Context.Services;
isStarted = true;
designPanel.StartInputAction();
RegisterEvents();
@ -125,6 +125,12 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -125,6 +125,12 @@ namespace ICSharpCode.WpfDesign.Designer.Services
protected override void OnStarted(MouseButtonEventArgs e)
{
base.OnStarted(e);
DesignItem item = designPanel.FindDesignedElementForOriginalSource(e.OriginalSource);
if (item != null) {
services.Selection.SetSelectedComponents(new DesignItem[] { item }, SelectionTypes.Auto);
} else {
services.Selection.SetSelectedComponents(new DesignItem[] { }, SelectionTypes.Auto);
}
}
protected override void OnStopped()

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj

@ -56,8 +56,10 @@ @@ -56,8 +56,10 @@
<Link>Configuration\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="Controls\AdornerLayer.cs" />
<Compile Include="Controls\SingleVisualChildElement.cs" />
<Compile Include="DesignPanel.cs" />
<Compile Include="Extensions\SelectedElementRectangleExtension.cs" />
<Compile Include="Extensions\TabItemClickableExtension.cs" />
<Compile Include="Linq.cs" />
<Compile Include="ServiceRequiredException.cs" />

117
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
// <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.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ICSharpCode.WpfDesign.Adorners
{
/// <summary>
/// Manages display of adorners on the design surface.
/// </summary>
public sealed class AdornerPanel : Panel
{
#region Attached Property Placement
/// <summary>
/// The dependency property used to store the placement of adorner visuals.
/// </summary>
public static readonly DependencyProperty PlacementProperty = DependencyProperty.RegisterAttached(
"Placement", typeof(Placement), typeof(AdornerPanel),
new FrameworkPropertyMetadata(new Placement(), FrameworkPropertyMetadataOptions.AffectsParentMeasure)
);
/// <summary>
/// Gets the placement of the specified adorner visual.
/// </summary>
public static Placement GetPlacement(Visual visual)
{
if (visual == null)
throw new ArgumentNullException("visual");
return (Placement)visual.GetValue(PlacementProperty);
}
/// <summary>
/// Sets the placement of the specified adorner visual.
/// </summary>
public static void SetPlacement(Visual visual, Placement placement)
{
if (visual == null)
throw new ArgumentNullException("visual");
if (placement == null)
throw new ArgumentNullException("placement");
visual.SetValue(PlacementProperty, placement);
}
#endregion
UIElement _adornedElement;
AdornerOrder _Order = AdornerOrder.Content;
public UIElement AdornedElement {
get { return _adornedElement; }
set { _adornedElement = value; }
}
public AdornerOrder Order {
get { return _Order; }
set { _Order = value; }
}
protected override Size MeasureOverride(Size availableSize)
{
if (this.AdornedElement != null) {
foreach (DependencyObject v in this.VisualChildren) {
UIElement e = v as UIElement;
if (e != null) {
e.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
}
}
return this.AdornedElement.RenderSize;
} else {
return base.MeasureOverride(availableSize);
}
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement element in base.InternalChildren) {
element.Arrange(new Rect(finalSize));
}
return finalSize;
}
private IEnumerable<DependencyObject> VisualChildren {
get {
int count = VisualTreeHelper.GetChildrenCount(this);
for (int i = 0; i < count; i++) {
yield return VisualTreeHelper.GetChild(this, i);
}
}
}
}
public struct AdornerOrder : IComparable<AdornerOrder>
{
public static readonly AdornerOrder Background = new AdornerOrder(100);
public static readonly AdornerOrder Content = new AdornerOrder(200);
public static readonly AdornerOrder Foreground = new AdornerOrder(300);
int i;
public AdornerOrder(int i)
{
this.i = i;
}
public int CompareTo(AdornerOrder other)
{
return i.CompareTo(other.i);
}
}
}

145
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs

@ -0,0 +1,145 @@ @@ -0,0 +1,145 @@
// <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.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Adorners
{
/// <summary>
/// Base class for extensions that present adorners on the screen.
/// </summary>
/// <remarks>
/// About design-time adorners and their placement:
/// read http://myfun.spaces.live.com/blog/cns!AC1291870308F748!240.entry
/// and http://myfun.spaces.live.com/blog/cns!AC1291870308F748!242.entry
/// </remarks>
public abstract class AdornerProvider : DefaultExtension
{
#region class AdornerCollection
/// <summary>
/// Describes a collection of adorner visuals.
/// </summary>
sealed class AdornerPanelCollection : Collection<AdornerPanel>
{
readonly AdornerProvider _provider;
internal AdornerPanelCollection(AdornerProvider provider)
{
this._provider = provider;
}
/// <summary/>
protected override void InsertItem(int index, AdornerPanel item)
{
base.InsertItem(index, item);
_provider.OnAdornerAdd(item);
}
/// <summary/>
protected override void RemoveItem(int index)
{
_provider.OnAdornerRemove(base[index]);
base.RemoveItem(index);
}
/// <summary/>
protected override void SetItem(int index, AdornerPanel item)
{
_provider.OnAdornerRemove(base[index]);
base.SetItem(index, item);
_provider.OnAdornerAdd(item);
}
/// <summary/>
protected override void ClearItems()
{
foreach (AdornerPanel v in this) {
_provider.OnAdornerRemove(v);
}
base.ClearItems();
}
}
#endregion
AdornerPanelCollection _adorners;
bool isVisible;
/// <summary>
/// Creates a new AdornerProvider instance.
/// </summary>
public AdornerProvider()
{
_adorners = new AdornerPanelCollection(this);
}
/// <summary>
/// Is called after the ExtendedItem was set.
/// This methods displays the registered adorners
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
isVisible = true;
foreach (AdornerPanel v in _adorners) {
OnAdornerAdd(v);
}
}
/// <summary>
/// Is called when the extension is removed.
/// This method hides the registered adorners.
/// </summary>
protected override void OnRemove()
{
base.OnRemove();
foreach (AdornerPanel v in _adorners) {
OnAdornerRemove(v);
}
isVisible = false;
}
/// <summary>
/// Gets the list of adorners displayed by this AdornerProvider.
/// </summary>
public Collection<AdornerPanel> Adorners {
get { return _adorners; }
}
/// <summary>
/// Adds an UIElement as adorner with the specified placement.
/// </summary>
protected void AddAdorner(UIElement adorner, Placement placement)
{
AdornerPanel.SetPlacement(adorner, placement);
AdornerPanel p = new AdornerPanel();
p.Children.Add(adorner);
this.Adorners.Add(p);
}
internal void OnAdornerAdd(AdornerPanel item)
{
if (!isVisible) return;
item.AdornedElement = this.ExtendedItem.View;
IDesignPanel avs = Services.GetService<IDesignPanel>();
avs.Adorners.Add(item);
}
internal void OnAdornerRemove(AdornerPanel item)
{
if (!isVisible) return;
IDesignPanel avs = Services.GetService<IDesignPanel>();
avs.Adorners.Remove(item);
}
}
}

50
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProviderClasses.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// <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 ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Adorners
{
// Some classes that derive from AdornerProvider to specify a certain ExtensionServer.
/// <summary>
/// An adorner extension that is attached permanently.
/// </summary>
[ExtensionServer(typeof(DefaultExtensionServer.Permanent))]
public abstract class PermanentAdornerProvider : AdornerProvider
{
}
/// <summary>
/// An adorner extension that is attached to selected components.
/// </summary>
[ExtensionServer(typeof(SelectionExtensionServer))]
public abstract class SelectionAdornerProvider : AdornerProvider
{
}
/// <summary>
/// An adorner extension that is attached to the primary selection.
/// </summary>
[ExtensionServer(typeof(PrimarySelectionExtensionServer))]
public abstract class PrimarySelectionAdornerProvider : AdornerProvider
{
}
/// <summary>
/// An adorner extension that is attached to the secondary selection.
/// </summary>
[ExtensionServer(typeof(SecondarySelectionExtensionServer))]
public abstract class SecondarySelectionAdornerProvider : AdornerProvider
{
}
}

150
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/Placement.cs

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
// <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.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
namespace ICSharpCode.WpfDesign.Adorners
{
// We have to support the different coordinate spaces as explained in
// http://myfun.spaces.live.com/blog/cns!AC1291870308F748!242.entry
/// <summary>
/// Defines how a design-time adorner is placed.
/// </summary>
public class Placement
{
PlacementSpace space = PlacementSpace.Render;
/// <summary>
/// Gets/Sets the space in which the adorner is placed.
/// </summary>
public PlacementSpace Space {
get { return space; }
set { space = value; }
}
double widthRelativeToDesiredWidth, heightRelativeToDesiredHeight;
/// <summary>
/// Gets/Sets the width of the adorner relative to the desired adorner width.
/// </summary>
public double WidthRelativeToDesiredWidth {
get { return widthRelativeToDesiredWidth; }
set { widthRelativeToDesiredWidth = value; }
}
/// <summary>
/// Gets/Sets the height of the adorner relative to the desired adorner height.
/// </summary>
public double HeightRelativeToDesiredHeight {
get { return heightRelativeToDesiredHeight; }
set { heightRelativeToDesiredHeight = value; }
}
double widthRelativeToContentWidth, heightRelativeToContentHeight;
/// <summary>
/// Gets/Sets the width of the adorner relative to the width of the adorned item.
/// </summary>
public double WidthRelativeToContentWidth {
get { return widthRelativeToContentWidth; }
set { widthRelativeToContentWidth = value; }
}
/// <summary>
/// Gets/Sets the height of the adorner relative to the height of the adorned item.
/// </summary>
public double HeightRelativeToContentHeight {
get { return heightRelativeToContentHeight; }
set { heightRelativeToContentHeight = value; }
}
double widthOffset, heightOffset;
/// <summary>
/// Gets/Sets an offset that is added to the adorner width for the size calculation.
/// </summary>
public double WidthOffset {
get { return widthOffset; }
set { widthOffset = value; }
}
/// <summary>
/// Gets/Sets an offset that is added to the adorner height for the size calculation.
/// </summary>
public double HeightOffset {
get { return heightOffset; }
set { heightOffset = value; }
}
Size CalculateSize(Visual adornerVisual, UIElement adornedElement)
{
Size size = new Size(widthOffset, heightOffset);
if (widthRelativeToDesiredWidth != 0 || heightRelativeToDesiredHeight != 0) {
UIElement adornerElement = adornerVisual as UIElement;
if (adornerElement == null) {
throw new DesignerException("Cannot calculate the size relative to the adorner's desired size if the adorner is not an UIElement.");
}
size.Width += widthRelativeToDesiredWidth * adornerElement.DesiredSize.Width;
size.Height += heightRelativeToDesiredHeight * adornerElement.DesiredSize.Height;
}
size.Width += widthRelativeToContentWidth * adornedElement.RenderSize.Width;
size.Height += heightRelativeToContentHeight * adornedElement.RenderSize.Height;
return size;
}
}
/// <summary>
/// Describes the space in which an adorner is placed.
/// </summary>
public enum PlacementSpace
{
/// <summary>
/// The adorner is affected by the render transform of the adorned element.
/// </summary>
Render,
/// <summary>
/// The adorner is affected by the layout transform of the adorned element.
/// </summary>
Layout,
/// <summary>
/// The adorner is not affected by transforms of designed controls.
/// </summary>
Designer
}
/// <summary>
/// The possible layers where adorners can be placed.
/// </summary>
public enum AdornerZLayer
{
/// <summary>
/// This layer is below the other adorner layers.
/// </summary>
Low,
/// <summary>
/// This layer is for normal background adorners.
/// </summary>
Normal,
/// <summary>
/// This layer is for selection adorners
/// </summary>
Selection,
/// <summary>
/// This layer is for primary selection adorners
/// </summary>
PrimarySelection,
/// <summary>
/// This layer is above the other layers.
/// It is used for temporary drawings, e.g. the selection frame while selecting multiple controls with the mouse.
/// </summary>
High
}
}

58
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs

@ -71,42 +71,56 @@ namespace ICSharpCode.WpfDesign @@ -71,42 +71,56 @@ namespace ICSharpCode.WpfDesign
}
}
internal void SetExtensionServers(ExtensionServer[] extensionServers)
internal void SetExtensionServers(ExtensionManager extensionManager, ExtensionServer[] extensionServers)
{
Debug.Assert(_extensionServers == null);
Debug.Assert(extensionServers != null);
_extensionServers = extensionServers;
_extensionServerIsApplied = new bool[extensionServers.Length];
}
internal void ApplyExtensions(ExtensionManager extensionManager)
{
Debug.Assert(_extensionServers != null);
for (int i = 0; i < _extensionServers.Length; i++) {
bool shouldApply = _extensionServers[i].ShouldApplyExtensions(this);
if (shouldApply != _extensionServerIsApplied[i]) {
ExtensionServer server = _extensionServers[i];
if (shouldApply) {
// add extensions
foreach (Extension ext in extensionManager.CreateExtensions(server, this)) {
_extensions.Add(new ExtensionEntry(ext, server));
}
} else {
// remove extensions
_extensions.RemoveAll(
delegate (ExtensionEntry entry) {
if (entry.Server == server) {
server.RemoveExtension(entry.Extension);
return true;
} else {
return false;
}
});
_extensionServerIsApplied[i] = shouldApply;
ApplyUnapplyExtensionServer(extensionManager, shouldApply, _extensionServers[i]);
}
}
}
internal void ReapplyExtensionServer(ExtensionManager extensionManager, ExtensionServer server)
{
for (int i = 0; i < _extensionServers.Length; i++) {
if (_extensionServers[i] == server) {
bool shouldApply = server.ShouldApplyExtensions(this);
if (shouldApply != _extensionServerIsApplied[i]) {
_extensionServerIsApplied[i] = shouldApply;
ApplyUnapplyExtensionServer(extensionManager, shouldApply, server);
}
}
}
}
private void ApplyUnapplyExtensionServer(ExtensionManager extensionManager, bool shouldApply, ExtensionServer server)
{
if (shouldApply) {
// add extensions
foreach (Extension ext in extensionManager.CreateExtensions(server, this)) {
_extensions.Add(new ExtensionEntry(ext, server));
}
} else {
// remove extensions
_extensions.RemoveAll(
delegate (ExtensionEntry entry) {
if (entry.Server == server) {
server.RemoveExtension(entry.Extension);
return true;
} else {
return false;
}
});
}
}
#endregion
#region Manage behavior

63
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs

@ -13,68 +13,9 @@ namespace ICSharpCode.WpfDesign.Extensions @@ -13,68 +13,9 @@ namespace ICSharpCode.WpfDesign.Extensions
/// Base class for extensions that provide a behavior interface for the designed item.
/// These extensions are always loaded. They must have an parameter-less constructor.
/// </summary>
[ExtensionServer(typeof(BehaviorExtension.BehaviorExtensionServer))]
public abstract class BehaviorExtension : Extension
[ExtensionServer(typeof(DefaultExtensionServer.Permanent))]
public abstract class BehaviorExtension : DefaultExtension
{
DesignItem _extendedItem;
/// <summary>
/// Gets the item that is being extended by the BehaviorExtension.
/// </summary>
public DesignItem ExtendedItem {
get {
if (_extendedItem == null)
throw new InvalidOperationException("Cannot access BehaviorExtension.ExtendedItem: " +
"The property is not initialized yet. Please move initialization logic " +
"that depends on ExtendedItem into the OnInitialized method.");
return _extendedItem;
}
}
/// <summary>
/// Gets the design context of the extended item. "Context" is equivalent to "ExtendedItem.Context".
/// </summary>
public DesignContext Context {
get {
return this.ExtendedItem.Context;
}
}
/// <summary>
/// Gets the service container of the extended item. "Services" is equivalent to "ExtendedItem.Services".
/// </summary>
public ServiceContainer Services {
get {
return this.ExtendedItem.Services;
}
}
/// <summary>
/// Is called after the ExtendedItem was set.
/// Override this method to register your behavior with the item.
/// </summary>
protected virtual void OnInitialized()
{
}
sealed class BehaviorExtensionServer : ExtensionServer
{
public override bool ShouldApplyExtensions(DesignItem extendedItem)
{
return true;
}
public override Extension CreateExtension(Type extensionType, DesignItem extendedItem)
{
BehaviorExtension ext = (BehaviorExtension)Activator.CreateInstance(extensionType);
ext._extendedItem = extendedItem;
ext.OnInitialized();
return ext;
}
public override void RemoveExtension(Extension extension)
{
}
}
}
}

114
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/DefaultExtension.cs

@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
// <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.Diagnostics;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Base class for extensions that have an parameter-less constructor and are initialized using the
/// OnInitialize method.
/// </summary>
public class DefaultExtension : Extension
{
DesignItem _extendedItem;
/// <summary>
/// Gets the item that is being extended by the BehaviorExtension.
/// </summary>
public DesignItem ExtendedItem {
get {
if (_extendedItem == null)
throw new InvalidOperationException("Cannot access BehaviorExtension.ExtendedItem: " +
"The property is not initialized yet. Please move initialization logic " +
"that depends on ExtendedItem into the OnInitialized method.");
return _extendedItem;
}
}
/// <summary>
/// Gets the design context of the extended item. "Context" is equivalent to "ExtendedItem.Context".
/// </summary>
public DesignContext Context {
get {
return this.ExtendedItem.Context;
}
}
/// <summary>
/// Gets the service container of the extended item. "Services" is equivalent to "ExtendedItem.Services".
/// </summary>
public ServiceContainer Services {
get {
return this.ExtendedItem.Services;
}
}
/// <summary>
/// Is called after the ExtendedItem was set.
/// Override this method to register your behavior with the item.
/// </summary>
protected virtual void OnInitialized()
{
}
/// <summary>
/// Is called when the extension is removed.
/// </summary>
protected virtual void OnRemove()
{
}
internal void CallOnRemove() { OnRemove(); }
internal void InitializeDefaultExtension(DesignItem extendedItem)
{
Debug.Assert(this._extendedItem == null);
Debug.Assert(extendedItem != null);
this._extendedItem = extendedItem;
OnInitialized();
}
}
/// <summary>
/// Base class for extension servers that create extensions that derive from <see cref="DefaultExtension"/>.
/// </summary>
public abstract class DefaultExtensionServer : ExtensionServer
{
/// <summary>
/// Creates an instance of the DefaultExtension and calls OnInitialize on it.
/// </summary>
public override Extension CreateExtension(Type extensionType, DesignItem extendedItem)
{
DefaultExtension ext = (DefaultExtension)Activator.CreateInstance(extensionType);
ext.InitializeDefaultExtension(extendedItem);
return ext;
}
/// <summary>
/// Calls OnRemove() on the DefaultExtension.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
public override void RemoveExtension(Extension extension)
{
Debug.Assert(extension != null);
Debug.Assert(extension is DefaultExtension);
((DefaultExtension)extension).CallOnRemove();
}
internal sealed class Permanent : DefaultExtensionServer
{
public override bool ShouldApplyExtensions(DesignItem extendedItem)
{
return true;
}
}
}
}

22
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs

@ -32,8 +32,17 @@ namespace ICSharpCode.WpfDesign.Extensions @@ -32,8 +32,17 @@ namespace ICSharpCode.WpfDesign.Extensions
void OnComponentRegistered(object sender, DesignItemEventArgs e)
{
e.Item.SetExtensionServers(GetExtensionServersForItem(e.Item));
e.Item.ApplyExtensions(this);
e.Item.SetExtensionServers(this, GetExtensionServersForItem(e.Item));
}
/// <summary>
/// Re-applies extensions from the ExtensionServer to the specified design items.
/// </summary>
public void ReapplyExtensions(IEnumerable<DesignItem> items, ExtensionServer server)
{
foreach (DesignItem item in items) {
item.ReapplyExtensionServer(this, server);
}
}
#region Manage ExtensionEntries
@ -173,10 +182,11 @@ namespace ICSharpCode.WpfDesign.Extensions @@ -173,10 +182,11 @@ namespace ICSharpCode.WpfDesign.Extensions
{
Debug.Assert(extensionType != null);
foreach (ExtensionServerAttribute esa in extensionType.GetCustomAttributes(typeof(ExtensionServerAttribute), true)) {
return GetExtensionServer(esa);
}
throw new DesignerException("Extension types must have a [ExtensionServer] attribute.");
object[] extensionServerAttributes = extensionType.GetCustomAttributes(typeof(ExtensionServerAttribute), true);
if (extensionServerAttributes.Length != 1)
throw new DesignerException("Extension types must have exactly one [ExtensionServer] attribute.");
return GetExtensionServer((ExtensionServerAttribute)extensionServerAttributes[0]);
}
/// <summary>

93
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/SelectionExtensionServer.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
// <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;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Applies an extension to the selected components.
/// </summary>
public class SelectionExtensionServer : DefaultExtensionServer
{
/// <summary>
/// Is called after the extension server is initialized and the Context property has been set.
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Services.Selection.SelectionChanged += OnSelectionChanged;
}
void OnSelectionChanged(object sender, DesignItemCollectionEventArgs e)
{
Services.ExtensionManager.ReapplyExtensions(e.Items, this);
}
/// <summary>
/// Gets if the item is selected.
/// </summary>
public override bool ShouldApplyExtensions(DesignItem extendedItem)
{
return Services.Selection.IsComponentSelected(extendedItem);
}
}
/// <summary>
/// Applies an extension to the selected components, but not to the primary selection.
/// </summary>
public class SecondarySelectionExtensionServer : SelectionExtensionServer
{
/// <summary>
/// Gets if the item is in the secondary selection.
/// </summary>
public override bool ShouldApplyExtensions(DesignItem extendedItem)
{
return base.ShouldApplyExtensions(extendedItem) && Services.Selection.PrimarySelection != extendedItem;
}
}
/// <summary>
/// Applies an extension to the primary selection.
/// </summary>
public class PrimarySelectionExtensionServer : DefaultExtensionServer
{
DesignItem oldPrimarySelection;
/// <summary>
/// Is called after the extension server is initialized and the Context property has been set.
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
this.Services.Selection.PrimarySelectionChanged += OnPrimarySelectionChanged;
}
void OnPrimarySelectionChanged(object sender, EventArgs e)
{
DesignItem newPrimarySelection = this.Services.Selection.PrimarySelection;
if (oldPrimarySelection != newPrimarySelection) {
if (oldPrimarySelection == null) {
this.Services.ExtensionManager.ReapplyExtensions(new DesignItem[] { newPrimarySelection }, this);
} else if (newPrimarySelection == null) {
this.Services.ExtensionManager.ReapplyExtensions(new DesignItem[] { oldPrimarySelection }, this);
} else {
this.Services.ExtensionManager.ReapplyExtensions(new DesignItem[] { oldPrimarySelection, newPrimarySelection }, this);
}
oldPrimarySelection = newPrimarySelection;
}
}
/// <summary>
/// Gets if the item is the primary selection.
/// </summary>
public override bool ShouldApplyExtensions(DesignItem extendedItem)
{
return Services.Selection.PrimarySelection == extendedItem;
}
}
}

1
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Services.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
namespace ICSharpCode.WpfDesign
{

6
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs

@ -6,8 +6,10 @@ @@ -6,8 +6,10 @@
// </file>
using System;
using System.Collections.Generic;
using System.Windows.Input;
using System.Windows;
using ICSharpCode.WpfDesign.Adorners;
namespace ICSharpCode.WpfDesign
{
@ -118,6 +120,10 @@ namespace ICSharpCode.WpfDesign @@ -118,6 +120,10 @@ namespace ICSharpCode.WpfDesign
/// </summary>
DesignItem FindDesignedElementForOriginalSource(object originalSource);
/// <summary>
/// Gets the list of adorners displayed on the design panel.
/// </summary>
ICollection<AdornerPanel> Adorners { get; }
// The following members were missing in <see cref="IInputElement"/>, but of course
// are supported on the DesignPanel:

7
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

@ -57,17 +57,23 @@ @@ -57,17 +57,23 @@
<Compile Include="..\..\..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>Configuration\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Adorners\AdornerPanel.cs" />
<Compile Include="Adorners\AdornerProvider.cs" />
<Compile Include="Adorners\AdornerProviderClasses.cs" />
<Compile Include="Adorners\Placement.cs" />
<Compile Include="DesignContext.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="DesignerException.cs" />
<Compile Include="Extensions\BehaviorExtension.cs" />
<Compile Include="Extensions\CustomInstanceFactory.cs" />
<Compile Include="Extensions\DefaultExtension.cs" />
<Compile Include="Extensions\Extension.cs" />
<Compile Include="Extensions\ExtensionForAttribute.cs" />
<Compile Include="Extensions\ExtensionManager.cs" />
<Compile Include="Extensions\ExtensionServer.cs" />
<Compile Include="Extensions\ExtensionServerAttribute.cs" />
<Compile Include="Extensions\SelectionExtensionServer.cs" />
<Compile Include="HashSet.cs" />
<Compile Include="Linq.cs" />
<Compile Include="ServiceContainer.cs" />
@ -78,5 +84,6 @@ @@ -78,5 +84,6 @@
<ItemGroup>
<Folder Include="Configuration" />
<Folder Include="Extensions" />
<Folder Include="Adorners" />
</ItemGroup>
</Project>
Loading…
Cancel
Save