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. 103
      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. 79
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Adorners/Placement.cs
  8. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Tools.cs

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

@ -89,12 +89,31 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -89,12 +89,31 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
AdornerPanelCollection _adorners;
readonly UIElement _designPanel;
#if DEBUG
int _totalAdornerCount;
#endif
internal AdornerLayer(UIElement designPanel)
{
this._designPanel = designPanel;
this.LayoutUpdated += OnLayoutUpdated;
_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 {
@ -106,22 +125,32 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -106,22 +125,32 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
sealed class AdornerInfo
{
internal readonly List<AdornerPanel> adorners = new List<AdornerPanel>();
internal bool isVisible;
}
// adorned element => AdornerInfo
Dictionary<UIElement, AdornerInfo> _dict;
Dictionary<UIElement, AdornerInfo> _dict = new Dictionary<UIElement, AdornerInfo>();
void ClearAdorners()
{
if (_dict.Count == 0)
return; // already empty
this.Children.Clear();
_dict = new Dictionary<UIElement, AdornerInfo>();
#if DEBUG
_totalAdornerCount = 0;
Debug.WriteLine("AdornerLayer cleared.");
#endif
}
AdornerInfo GetAdornerInfo(UIElement adornedElement)
AdornerInfo GetOrCreateAdornerInfo(UIElement adornedElement)
{
AdornerInfo info;
if (!_dict.TryGetValue(adornedElement, out info)) {
info = _dict[adornedElement] = new AdornerInfo();
info.isVisible = adornedElement.IsDescendantOf(_designPanel);
}
return info;
}
@ -138,8 +167,19 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -138,8 +167,19 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
if (adornerPanel.AdornedElement == null)
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;
int i = 0;
for (i = 0; i < children.Count; i++) {
@ -149,8 +189,6 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -149,8 +189,6 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
}
}
children.Insert(i, adornerPanel);
this.InvalidateMeasure();
}
protected override Size MeasureOverride(Size availableSize)
@ -166,7 +204,9 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -166,7 +204,9 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
{
foreach (AdornerPanel adorner in this.Children) {
adorner.Arrange(new Rect(new Point(0, 0), adorner.DesiredSize));
adorner.RenderTransform = (Transform)adorner.AdornedElement.TransformToAncestor(_designPanel);
if (adorner.AdornedElement.IsDescendantOf(_designPanel)) {
adorner.RenderTransform = (Transform)adorner.AdornedElement.TransformToAncestor(_designPanel);
}
}
return finalSize;
}
@ -181,11 +221,58 @@ namespace ICSharpCode.WpfDesign.Designer.Controls @@ -181,11 +221,58 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
return false;
if (info.adorners.Remove(adornerPanel)) {
this.Children.Remove(adornerPanel);
if (info.isVisible) {
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;
} else {
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 @@ -37,8 +37,9 @@ namespace ICSharpCode.WpfDesign.Designer
}
DesignContext _context;
EatAllHitTestRequests _eatAllHitTestRequests;
AdornerLayer _adornerLayer;
readonly EatAllHitTestRequests _eatAllHitTestRequests;
readonly AdornerLayer _adornerLayer;
readonly Canvas _markerCanvas;
public DesignPanel()
{
@ -46,6 +47,8 @@ namespace ICSharpCode.WpfDesign.Designer @@ -46,6 +47,8 @@ namespace ICSharpCode.WpfDesign.Designer
_eatAllHitTestRequests = new EatAllHitTestRequests();
_eatAllHitTestRequests.IsHitTestVisible = false;
_adornerLayer = new AdornerLayer(this);
_markerCanvas = new Canvas();
_markerCanvas.IsHitTestVisible = false;
}
#region Visual Child Management
@ -60,10 +63,12 @@ namespace ICSharpCode.WpfDesign.Designer @@ -60,10 +63,12 @@ namespace ICSharpCode.WpfDesign.Designer
// remove _adornerLayer and _eatAllHitTestRequests
RemoveVisualChild(_adornerLayer);
RemoveVisualChild(_eatAllHitTestRequests);
RemoveVisualChild(_markerCanvas);
} else if (base.Child == null) {
// Child is being set from null to some value
AddVisualChild(_adornerLayer);
AddVisualChild(_eatAllHitTestRequests);
AddVisualChild(_markerCanvas);
}
base.Child = value;
}
@ -78,6 +83,8 @@ namespace ICSharpCode.WpfDesign.Designer @@ -78,6 +83,8 @@ namespace ICSharpCode.WpfDesign.Designer
return _eatAllHitTestRequests;
else if (index == 2)
return _adornerLayer;
else if (index == 3)
return _markerCanvas;
}
return base.GetVisualChild(index);
}
@ -85,7 +92,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -85,7 +92,7 @@ namespace ICSharpCode.WpfDesign.Designer
protected override int VisualChildrenCount {
get {
if (base.Child != null)
return 3;
return 4;
else
return base.VisualChildrenCount;
}
@ -97,6 +104,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -97,6 +104,7 @@ namespace ICSharpCode.WpfDesign.Designer
if (this.Child != null) {
_adornerLayer.Measure(constraint);
_eatAllHitTestRequests.Measure(constraint);
_markerCanvas.Measure(constraint);
}
return result;
}
@ -105,8 +113,10 @@ namespace ICSharpCode.WpfDesign.Designer @@ -105,8 +113,10 @@ namespace ICSharpCode.WpfDesign.Designer
{
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));
Rect r = new Rect(new Point(0, 0), arrangeSize);
_adornerLayer.Arrange(r);
_eatAllHitTestRequests.Arrange(r);
_markerCanvas.Arrange(r);
}
return result;
}
@ -197,6 +207,10 @@ namespace ICSharpCode.WpfDesign.Designer @@ -197,6 +207,10 @@ namespace ICSharpCode.WpfDesign.Designer
return _adornerLayer.Adorners;
}
}
public Canvas MarkerCanvas {
get { return _markerCanvas; }
}
}
internal delegate void Action();

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

@ -86,6 +86,7 @@ namespace ICSharpCode.WpfDesign.Designer @@ -86,6 +86,7 @@ namespace ICSharpCode.WpfDesign.Designer
_designContext = null;
_designPanel.Context = 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 @@ -33,9 +33,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
r.StrokeDashArray = new DoubleCollection(new double[] { 0, 2 });
r.IsHitTestVisible = false;
Placement placement = new Placement();
RelativePlacement placement = new RelativePlacement();
placement.WidthRelativeToContentWidth = 1;
placement.HeightRelativeToContentHeight = 1;
placement.WidthOffset = 2;
placement.HeightOffset = 2;
placement.XOffset = -1;
placement.YOffset = -1;
this.AddAdorner(r, placement);
}

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

@ -24,45 +24,56 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -24,45 +24,56 @@ namespace ICSharpCode.WpfDesign.Adorners
/// </summary>
public static readonly DependencyProperty PlacementProperty = DependencyProperty.RegisterAttached(
"Placement", typeof(Placement), typeof(AdornerPanel),
new FrameworkPropertyMetadata(new Placement(), FrameworkPropertyMetadataOptions.AffectsParentMeasure)
new FrameworkPropertyMetadata(Placement.FillContent, FrameworkPropertyMetadataOptions.AffectsParentMeasure)
);
/// <summary>
/// Gets the placement of the specified adorner visual.
/// Gets the placement of the specified adorner.
/// </summary>
public static Placement GetPlacement(Visual visual)
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
public static Placement GetPlacement(UIElement adorner)
{
if (visual == null)
throw new ArgumentNullException("visual");
return (Placement)visual.GetValue(PlacementProperty);
if (adorner == null)
throw new ArgumentNullException("adorner");
return (Placement)adorner.GetValue(PlacementProperty);
}
/// <summary>
/// Sets the placement of the specified adorner visual.
/// Sets the placement of the specified adorner.
/// </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)
throw new ArgumentNullException("visual");
if (adorner == null)
throw new ArgumentNullException("adorner");
if (placement == null)
throw new ArgumentNullException("placement");
visual.SetValue(PlacementProperty, placement);
adorner.SetValue(PlacementProperty, placement);
}
#endregion
UIElement _adornedElement;
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 {
get { return _adornedElement; }
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 {
get { return _Order; }
set { _Order = value; }
}
/// <summary/>
protected override Size MeasureOverride(Size availableSize)
{
if (this.AdornedElement != null) {
@ -78,37 +89,57 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -78,37 +89,57 @@ namespace ICSharpCode.WpfDesign.Adorners
}
}
/// <summary/>
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement element in base.InternalChildren) {
element.Arrange(new Rect(finalSize));
GetPlacement(element).Arrange(this, element, finalSize);
}
return finalSize;
}
private IEnumerable<DependencyObject> VisualChildren {
private DependencyObject[] VisualChildren {
get {
int count = VisualTreeHelper.GetChildrenCount(this);
for (int i = 0; i < count; i++) {
yield return VisualTreeHelper.GetChild(this, i);
DependencyObject[] children = new DependencyObject[count];
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>
{
/// <summary>
/// The adorner is in the background layer.
/// </summary>
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);
/// <summary>
/// The adorner is in the foreground layer.
/// </summary>
public static readonly AdornerOrder Foreground = new AdornerOrder(300);
int i;
public AdornerOrder(int i)
internal AdornerOrder(int i)
{
this.i = i;
}
/// <summary>
/// Compares the <see cref="AdornerOrder"/> to another AdornerOrder.
/// </summary>
public int CompareTo(AdornerOrder other)
{
return i.CompareTo(other.i);

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

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

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

@ -18,18 +18,33 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -18,18 +18,33 @@ namespace ICSharpCode.WpfDesign.Adorners
/// <summary>
/// Defines how a design-time adorner is placed.
/// </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>
/// Gets/Sets the space in which the adorner is placed.
/// Arranges the adorner element on the specified adorner panel.
/// </summary>
public PlacementSpace Space {
get { return space; }
set { space = value; }
}
public abstract void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize);
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;
/// <summary>
@ -84,23 +99,51 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -84,23 +99,51 @@ namespace ICSharpCode.WpfDesign.Adorners
set { heightOffset = value; }
}
Size CalculateSize(Visual adornerVisual, UIElement adornedElement)
Size CalculateSize(UIElement adorner, Size adornedElementSize)
{
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 += widthRelativeToDesiredWidth * adorner.DesiredSize.Width;
size.Height += heightRelativeToDesiredHeight * adorner.DesiredSize.Height;
}
size.Width += widthRelativeToContentWidth * adornedElement.RenderSize.Width;
size.Height += heightRelativeToContentHeight * adornedElement.RenderSize.Height;
size.Width += widthRelativeToContentWidth * adornedElementSize.Width;
size.Height += heightRelativeToContentHeight * adornedElementSize.Height;
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>
/// Describes the space in which an adorner is placed.
/// </summary>
@ -119,7 +162,7 @@ namespace ICSharpCode.WpfDesign.Adorners @@ -119,7 +162,7 @@ namespace ICSharpCode.WpfDesign.Adorners
/// </summary>
Designer
}
/// <summary>
/// The possible layers where adorners can be placed.
/// </summary>

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

@ -125,6 +125,14 @@ namespace ICSharpCode.WpfDesign @@ -125,6 +125,14 @@ namespace ICSharpCode.WpfDesign
/// </summary>
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
// are supported on the DesignPanel:

Loading…
Cancel
Save