Browse Source

More work on adorners.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2228 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
2ecc05f3f5
  1. 99
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/AdornerLayer.cs
  2. 24
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignPanel.cs
  3. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/DesignSurface.cs
  4. 7
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SelectedElementRectangleExtension.cs
  5. 63
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerPanel.cs
  6. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/AdornerProvider.cs
  7. 73
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/Placement.cs
  8. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs

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

@ -89,12 +89,31 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
AdornerPanelCollection _adorners; AdornerPanelCollection _adorners;
readonly UIElement _designPanel; readonly UIElement _designPanel;
#if DEBUG
int _totalAdornerCount;
#endif
internal AdornerLayer(UIElement designPanel) internal AdornerLayer(UIElement designPanel)
{ {
this._designPanel = designPanel; this._designPanel = designPanel;
this.LayoutUpdated += OnLayoutUpdated;
_adorners = new AdornerPanelCollection(this); _adorners = new AdornerPanelCollection(this);
ClearAdorners(); }
void OnLayoutUpdated(object sender, EventArgs e)
{
UpdateAllAdorners(false);
// Debug.WriteLine("Adorner LayoutUpdated. AdornedElements=" + _dict.Count +
// ", visible adorners=" + VisualChildrenCount + ", total adorners=" + (_totalAdornerCount));
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
UpdateAllAdorners(true);
} }
internal AdornerPanelCollection Adorners { internal AdornerPanelCollection Adorners {
@ -106,22 +125,32 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
sealed class AdornerInfo sealed class AdornerInfo
{ {
internal readonly List<AdornerPanel> adorners = new List<AdornerPanel>(); internal readonly List<AdornerPanel> adorners = new List<AdornerPanel>();
internal bool isVisible;
} }
// adorned element => AdornerInfo // adorned element => AdornerInfo
Dictionary<UIElement, AdornerInfo> _dict; Dictionary<UIElement, AdornerInfo> _dict = new Dictionary<UIElement, AdornerInfo>();
void ClearAdorners() void ClearAdorners()
{ {
if (_dict.Count == 0)
return; // already empty
this.Children.Clear(); this.Children.Clear();
_dict = new Dictionary<UIElement, AdornerInfo>(); _dict = new Dictionary<UIElement, AdornerInfo>();
#if DEBUG
_totalAdornerCount = 0;
Debug.WriteLine("AdornerLayer cleared.");
#endif
} }
AdornerInfo GetAdornerInfo(UIElement adornedElement) AdornerInfo GetOrCreateAdornerInfo(UIElement adornedElement)
{ {
AdornerInfo info; AdornerInfo info;
if (!_dict.TryGetValue(adornedElement, out info)) { if (!_dict.TryGetValue(adornedElement, out info)) {
info = _dict[adornedElement] = new AdornerInfo(); info = _dict[adornedElement] = new AdornerInfo();
info.isVisible = adornedElement.IsDescendantOf(_designPanel);
} }
return info; return info;
} }
@ -138,8 +167,19 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
if (adornerPanel.AdornedElement == null) if (adornerPanel.AdornedElement == null)
throw new DesignerException("adornerPanel.AdornedElement must be set"); throw new DesignerException("adornerPanel.AdornedElement must be set");
GetAdornerInfo(adornerPanel.AdornedElement).adorners.Add(adornerPanel); AdornerInfo info = GetOrCreateAdornerInfo(adornerPanel.AdornedElement);
info.adorners.Add(adornerPanel);
if (info.isVisible) {
AddAdornerToChildren(adornerPanel);
}
Debug.WriteLine("Adorner added. AdornedElements=" + _dict.Count +
", visible adorners=" + VisualChildrenCount + ", total adorners=" + (++_totalAdornerCount));
}
void AddAdornerToChildren(AdornerPanel adornerPanel)
{
UIElementCollection children = this.Children; UIElementCollection children = this.Children;
int i = 0; int i = 0;
for (i = 0; i < children.Count; i++) { for (i = 0; i < children.Count; i++) {
@ -149,8 +189,6 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
} }
} }
children.Insert(i, adornerPanel); children.Insert(i, adornerPanel);
this.InvalidateMeasure();
} }
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
@ -166,8 +204,10 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
{ {
foreach (AdornerPanel adorner in this.Children) { foreach (AdornerPanel adorner in this.Children) {
adorner.Arrange(new Rect(new Point(0, 0), adorner.DesiredSize)); adorner.Arrange(new Rect(new Point(0, 0), adorner.DesiredSize));
if (adorner.AdornedElement.IsDescendantOf(_designPanel)) {
adorner.RenderTransform = (Transform)adorner.AdornedElement.TransformToAncestor(_designPanel); adorner.RenderTransform = (Transform)adorner.AdornedElement.TransformToAncestor(_designPanel);
} }
}
return finalSize; return finalSize;
} }
@ -181,11 +221,58 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
return false; return false;
if (info.adorners.Remove(adornerPanel)) { if (info.adorners.Remove(adornerPanel)) {
if (info.isVisible) {
this.Children.Remove(adornerPanel); this.Children.Remove(adornerPanel);
}
if (info.adorners.Count == 0) {
_dict.Remove(adornerPanel.AdornedElement);
}
Debug.WriteLine("Adorner removed. AdornedElements=" + _dict.Count +
", visible adorners=" + VisualChildrenCount + ", total adorners=" + (--_totalAdornerCount));
return true; return true;
} else { } else {
return false; return false;
} }
} }
public void UpdateAdornersForElement(UIElement element, bool forceInvalidate)
{
AdornerInfo info = GetExistingAdornerInfo(element);
if (info != null) {
UpdateAdornersForElement(element, info, forceInvalidate);
}
}
void UpdateAdornersForElement(UIElement element, AdornerInfo info, bool forceInvalidate)
{
if (element.IsDescendantOf(_designPanel)) {
if (!info.isVisible) {
info.isVisible = true;
// make adorners visible:
info.adorners.ForEach(AddAdornerToChildren);
}
if (forceInvalidate) {
foreach (AdornerPanel p in info.adorners) {
p.InvalidateMeasure();
}
}
} else {
if (info.isVisible) {
info.isVisible = false;
// make adorners invisible:
info.adorners.ForEach(this.Children.Remove);
}
}
}
void UpdateAllAdorners(bool forceInvalidate)
{
foreach (KeyValuePair<UIElement, AdornerInfo> pair in _dict) {
UpdateAdornersForElement(pair.Key, pair.Value, forceInvalidate);
}
}
} }
} }

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

@ -37,8 +37,9 @@ namespace ICSharpCode.WpfDesign.Designer
} }
DesignContext _context; DesignContext _context;
EatAllHitTestRequests _eatAllHitTestRequests; readonly EatAllHitTestRequests _eatAllHitTestRequests;
AdornerLayer _adornerLayer; readonly AdornerLayer _adornerLayer;
readonly Canvas _markerCanvas;
public DesignPanel() public DesignPanel()
{ {
@ -46,6 +47,8 @@ namespace ICSharpCode.WpfDesign.Designer
_eatAllHitTestRequests = new EatAllHitTestRequests(); _eatAllHitTestRequests = new EatAllHitTestRequests();
_eatAllHitTestRequests.IsHitTestVisible = false; _eatAllHitTestRequests.IsHitTestVisible = false;
_adornerLayer = new AdornerLayer(this); _adornerLayer = new AdornerLayer(this);
_markerCanvas = new Canvas();
_markerCanvas.IsHitTestVisible = false;
} }
#region Visual Child Management #region Visual Child Management
@ -60,10 +63,12 @@ namespace ICSharpCode.WpfDesign.Designer
// remove _adornerLayer and _eatAllHitTestRequests // remove _adornerLayer and _eatAllHitTestRequests
RemoveVisualChild(_adornerLayer); RemoveVisualChild(_adornerLayer);
RemoveVisualChild(_eatAllHitTestRequests); RemoveVisualChild(_eatAllHitTestRequests);
RemoveVisualChild(_markerCanvas);
} else if (base.Child == null) { } else if (base.Child == null) {
// Child is being set from null to some value // Child is being set from null to some value
AddVisualChild(_adornerLayer); AddVisualChild(_adornerLayer);
AddVisualChild(_eatAllHitTestRequests); AddVisualChild(_eatAllHitTestRequests);
AddVisualChild(_markerCanvas);
} }
base.Child = value; base.Child = value;
} }
@ -78,6 +83,8 @@ namespace ICSharpCode.WpfDesign.Designer
return _eatAllHitTestRequests; return _eatAllHitTestRequests;
else if (index == 2) else if (index == 2)
return _adornerLayer; return _adornerLayer;
else if (index == 3)
return _markerCanvas;
} }
return base.GetVisualChild(index); return base.GetVisualChild(index);
} }
@ -85,7 +92,7 @@ namespace ICSharpCode.WpfDesign.Designer
protected override int VisualChildrenCount { protected override int VisualChildrenCount {
get { get {
if (base.Child != null) if (base.Child != null)
return 3; return 4;
else else
return base.VisualChildrenCount; return base.VisualChildrenCount;
} }
@ -97,6 +104,7 @@ namespace ICSharpCode.WpfDesign.Designer
if (this.Child != null) { if (this.Child != null) {
_adornerLayer.Measure(constraint); _adornerLayer.Measure(constraint);
_eatAllHitTestRequests.Measure(constraint); _eatAllHitTestRequests.Measure(constraint);
_markerCanvas.Measure(constraint);
} }
return result; return result;
} }
@ -105,8 +113,10 @@ namespace ICSharpCode.WpfDesign.Designer
{ {
Size result = base.ArrangeOverride(arrangeSize); Size result = base.ArrangeOverride(arrangeSize);
if (this.Child != null) { if (this.Child != null) {
_adornerLayer.Arrange(new Rect(new Point(0, 0), arrangeSize)); Rect r = new Rect(new Point(0, 0), arrangeSize);
_eatAllHitTestRequests.Arrange(new Rect(new Point(0, 0), arrangeSize)); _adornerLayer.Arrange(r);
_eatAllHitTestRequests.Arrange(r);
_markerCanvas.Arrange(r);
} }
return result; return result;
} }
@ -197,6 +207,10 @@ namespace ICSharpCode.WpfDesign.Designer
return _adornerLayer.Adorners; return _adornerLayer.Adorners;
} }
} }
public Canvas MarkerCanvas {
get { return _markerCanvas; }
}
} }
internal delegate void Action(); internal delegate void Action();

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

@ -86,6 +86,7 @@ namespace ICSharpCode.WpfDesign.Designer
_designContext = null; _designContext = null;
_designPanel.Context = null; _designPanel.Context = null;
_designPanel.Child = null; _designPanel.Child = null;
_designPanel.Adorners.Clear();
} }
} }
} }

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

@ -33,9 +33,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
r.StrokeDashArray = new DoubleCollection(new double[] { 0, 2 }); r.StrokeDashArray = new DoubleCollection(new double[] { 0, 2 });
r.IsHitTestVisible = false; r.IsHitTestVisible = false;
Placement placement = new Placement(); RelativePlacement placement = new RelativePlacement();
placement.WidthRelativeToContentWidth = 1; placement.WidthRelativeToContentWidth = 1;
placement.HeightRelativeToContentHeight = 1; placement.HeightRelativeToContentHeight = 1;
placement.WidthOffset = 2;
placement.HeightOffset = 2;
placement.XOffset = -1;
placement.YOffset = -1;
this.AddAdorner(r, placement); this.AddAdorner(r, placement);
} }

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

@ -24,45 +24,56 @@ namespace ICSharpCode.WpfDesign.Adorners
/// </summary> /// </summary>
public static readonly DependencyProperty PlacementProperty = DependencyProperty.RegisterAttached( public static readonly DependencyProperty PlacementProperty = DependencyProperty.RegisterAttached(
"Placement", typeof(Placement), typeof(AdornerPanel), "Placement", typeof(Placement), typeof(AdornerPanel),
new FrameworkPropertyMetadata(new Placement(), FrameworkPropertyMetadataOptions.AffectsParentMeasure) new FrameworkPropertyMetadata(Placement.FillContent, FrameworkPropertyMetadataOptions.AffectsParentMeasure)
); );
/// <summary> /// <summary>
/// Gets the placement of the specified adorner visual. /// Gets the placement of the specified adorner.
/// </summary> /// </summary>
public static Placement GetPlacement(Visual visual) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
public static Placement GetPlacement(UIElement adorner)
{ {
if (visual == null) if (adorner == null)
throw new ArgumentNullException("visual"); throw new ArgumentNullException("adorner");
return (Placement)visual.GetValue(PlacementProperty); return (Placement)adorner.GetValue(PlacementProperty);
} }
/// <summary> /// <summary>
/// Sets the placement of the specified adorner visual. /// Sets the placement of the specified adorner.
/// </summary> /// </summary>
public static void SetPlacement(Visual visual, Placement placement) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
public static void SetPlacement(UIElement adorner, Placement placement)
{ {
if (visual == null) if (adorner == null)
throw new ArgumentNullException("visual"); throw new ArgumentNullException("adorner");
if (placement == null) if (placement == null)
throw new ArgumentNullException("placement"); throw new ArgumentNullException("placement");
visual.SetValue(PlacementProperty, placement); adorner.SetValue(PlacementProperty, placement);
} }
#endregion #endregion
UIElement _adornedElement; UIElement _adornedElement;
AdornerOrder _Order = AdornerOrder.Content; AdornerOrder _Order = AdornerOrder.Content;
/// <summary>
/// Gets/Sets the element adorned by this AdornerPanel.
/// Do not change this property after the panel was added to an AdornerLayer!
/// </summary>
public UIElement AdornedElement { public UIElement AdornedElement {
get { return _adornedElement; } get { return _adornedElement; }
set { _adornedElement = value; } set { _adornedElement = value; }
} }
/// <summary>
/// Gets/Sets the order used to display the AdornerPanel relative to other AdornerPanels.
/// Do not change this property after the panel was added to an AdornerLayer!
/// </summary>
public AdornerOrder Order { public AdornerOrder Order {
get { return _Order; } get { return _Order; }
set { _Order = value; } set { _Order = value; }
} }
/// <summary/>
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (this.AdornedElement != null) { if (this.AdornedElement != null) {
@ -78,37 +89,57 @@ namespace ICSharpCode.WpfDesign.Adorners
} }
} }
/// <summary/>
protected override Size ArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize)
{ {
foreach (UIElement element in base.InternalChildren) { foreach (UIElement element in base.InternalChildren) {
element.Arrange(new Rect(finalSize)); GetPlacement(element).Arrange(this, element, finalSize);
} }
return finalSize; return finalSize;
} }
private IEnumerable<DependencyObject> VisualChildren { private DependencyObject[] VisualChildren {
get { get {
int count = VisualTreeHelper.GetChildrenCount(this); int count = VisualTreeHelper.GetChildrenCount(this);
for (int i = 0; i < count; i++) { DependencyObject[] children = new DependencyObject[count];
yield return VisualTreeHelper.GetChild(this, i); for (int i = 0; i < children.Length; i++) {
children[i] = VisualTreeHelper.GetChild(this, i);
} }
return children;
} }
} }
} }
/// <summary>
/// Describes where an Adorner is positioned on the Z-Layer.
/// </summary>
public struct AdornerOrder : IComparable<AdornerOrder> public struct AdornerOrder : IComparable<AdornerOrder>
{ {
/// <summary>
/// The adorner is in the background layer.
/// </summary>
public static readonly AdornerOrder Background = new AdornerOrder(100); public static readonly AdornerOrder Background = new AdornerOrder(100);
/// <summary>
/// The adorner is in the content layer.
/// </summary>
public static readonly AdornerOrder Content = new AdornerOrder(200); public static readonly AdornerOrder Content = new AdornerOrder(200);
/// <summary>
/// The adorner is in the foreground layer.
/// </summary>
public static readonly AdornerOrder Foreground = new AdornerOrder(300); public static readonly AdornerOrder Foreground = new AdornerOrder(300);
int i; int i;
public AdornerOrder(int i) internal AdornerOrder(int i)
{ {
this.i = i; this.i = i;
} }
/// <summary>
/// Compares the <see cref="AdornerOrder"/> to another AdornerOrder.
/// </summary>
public int CompareTo(AdornerOrder other) public int CompareTo(AdornerOrder other)
{ {
return i.CompareTo(other.i); return i.CompareTo(other.i);

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

@ -75,7 +75,7 @@ namespace ICSharpCode.WpfDesign.Adorners
/// <summary> /// <summary>
/// Creates a new AdornerProvider instance. /// Creates a new AdornerProvider instance.
/// </summary> /// </summary>
public AdornerProvider() protected AdornerProvider()
{ {
_adorners = new AdornerPanelCollection(this); _adorners = new AdornerPanelCollection(this);
} }

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

@ -18,18 +18,33 @@ namespace ICSharpCode.WpfDesign.Adorners
/// <summary> /// <summary>
/// Defines how a design-time adorner is placed. /// Defines how a design-time adorner is placed.
/// </summary> /// </summary>
public class Placement public abstract class Placement
{ {
PlacementSpace space = PlacementSpace.Render; /// <summary>
/// A placement instance that places the adorner above the content, using the same bounds as the content.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
public static readonly Placement FillContent = new FillContentPlacement();
/// <summary> /// <summary>
/// Gets/Sets the space in which the adorner is placed. /// Arranges the adorner element on the specified adorner panel.
/// </summary> /// </summary>
public PlacementSpace Space { public abstract void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize);
get { return space; }
set { space = value; } sealed class FillContentPlacement : Placement
{
public override void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize)
{
adorner.Arrange(new Rect(adornedElementSize));
}
}
} }
/// <summary>
/// Placement class providing properties for different kinds of relative placements.
/// </summary>
public sealed class RelativePlacement : Placement
{
double widthRelativeToDesiredWidth, heightRelativeToDesiredHeight; double widthRelativeToDesiredWidth, heightRelativeToDesiredHeight;
/// <summary> /// <summary>
@ -84,21 +99,49 @@ namespace ICSharpCode.WpfDesign.Adorners
set { heightOffset = value; } set { heightOffset = value; }
} }
Size CalculateSize(Visual adornerVisual, UIElement adornedElement) Size CalculateSize(UIElement adorner, Size adornedElementSize)
{ {
Size size = new Size(widthOffset, heightOffset); Size size = new Size(widthOffset, heightOffset);
if (widthRelativeToDesiredWidth != 0 || heightRelativeToDesiredHeight != 0) { if (widthRelativeToDesiredWidth != 0 || heightRelativeToDesiredHeight != 0) {
UIElement adornerElement = adornerVisual as UIElement; size.Width += widthRelativeToDesiredWidth * adorner.DesiredSize.Width;
if (adornerElement == null) { size.Height += heightRelativeToDesiredHeight * adorner.DesiredSize.Height;
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.Width += widthRelativeToContentWidth * adornedElementSize.Width;
size.Height += heightRelativeToContentHeight * adornedElement.RenderSize.Height; size.Height += heightRelativeToContentHeight * adornedElementSize.Height;
return size; return size;
} }
double xOffset, yOffset;
/// <summary>
/// Gets/Sets an offset that is added to the adorner position.
/// </summary>
public double XOffset {
get { return xOffset; }
set { xOffset = value; }
}
/// <summary>
/// Gets/Sets an offset that is added to the adorner position.
/// </summary>
public double YOffset {
get { return yOffset; }
set { yOffset = value; }
}
Point CalculatePosition(Size adornedElementSize, Size adornerSize)
{
return new Point(xOffset, yOffset);
}
/// <summary>
/// Arranges the adorner element on the specified adorner panel.
/// </summary>
public override void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize)
{
Size adornerSize = CalculateSize(adorner, adornedElementSize);
adorner.Arrange(new Rect(CalculatePosition(adornedElementSize, adornerSize), adornerSize));
}
} }
/// <summary> /// <summary>

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

@ -125,6 +125,14 @@ namespace ICSharpCode.WpfDesign
/// </summary> /// </summary>
ICollection<AdornerPanel> Adorners { get; } ICollection<AdornerPanel> Adorners { get; }
/*
/// <summary>
/// A canvas that is on top of the design surface and all adorners.
/// Used for temporary drawings that are not attached to any element, e.g. the selection frame.
/// </summary>
Canvas MarkerCanvas { get; }
*/
// The following members were missing in <see cref="IInputElement"/>, but of course // The following members were missing in <see cref="IInputElement"/>, but of course
// are supported on the DesignPanel: // are supported on the DesignPanel:

Loading…
Cancel
Save