Adorner layer BUG - more than 144 adorners are not supported
I've encountered a strange problem working with adorners: Somehow adorners are stop working after adding more than 144 adorners to the same adorner layer.
The code below is a custom-panel which simply arrange items like a UniformGrid. It also adds custom Adorner instances (SelectionAdorner) on each added item, which provides visual on item select. The SelectionAdorner holds an IsSelected dependency-property and changes it to true/false on left-mouse-click.The panel also provides several layouts: 1x1, 4x4, etc.
Adding 200 items (or more than 144) the problems begin![]()
I'm working on Windows XP 32bit SP2, Debug and Release.
Here is the code (create new WPF project/files to repro):
(Sorry for not be able to attach files)
// SelectionAdorner.cs
using
System;using
System.Collections.Generic;using
System.Text;using
System.Windows.Input;using
System.Windows;using
System.Windows.Media;using
System.Windows.Documents;namespace
AdornerRendering{
publicclassSelectionAdorner :Adorner
{
#region
Dependency Properties#region
IsSelected Property///Identifies the IsSelected dependency property
publicstaticreadonlyDependencyProperty IsSelectedProperty =
DependencyProperty.Register("IsSelected",typeof(bool),typeof(SelectionAdorner),
newFrameworkPropertyMetadata(false,FrameworkPropertyMetadataOptions.AffectsRender));
///description for IsSelected property
publicbool IsSelected
{
get {return (bool)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty,value); }
}
#endregion
#endregion
#region
Initializationpublic SelectionAdorner(UIElement adornedElement) :base(adornedElement) { }
#endregion
#region
Overridesprotectedoverridevoid OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
IsSelected = !IsSelected;
base.OnMouseLeftButtonDown(e);
}
protectedoverridevoid OnRender(DrawingContext drawingContext)
{
Pen bluePen =newPen(Brushes.Blue, 1.0);
bluePen.Freeze();
drawingContext.DrawRectangle(Brushes.Transparent, bluePen,newRect(newPoint(), RenderSize));
if (IsSelected)
{
double thickness = 2.5;
// Draws the Active Border
Pen selectedBorderPen =newPen(Brushes.Red, thickness);
selectedBorderPen.Freeze();
double x = thickness * 0.5;
PathGeometry pathGeometry =newPathGeometry();
double lineLength = RenderSize.Height / 8;
pathGeometry.AddGeometry(newLineGeometry(newPoint(x, 0),newPoint(x, lineLength)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(0, x),newPoint(lineLength, x)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(RenderSize.Width - x, 0),newPoint(RenderSize.Width - x, lineLength)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(RenderSize.Width, x),newPoint(RenderSize.Width - lineLength - x, x)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(0, RenderSize.Height - x),newPoint(lineLength, RenderSize.Height - x)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(x, RenderSize.Height),newPoint(x, RenderSize.Height - lineLength)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(RenderSize.Width - x, RenderSize.Height),newPoint(RenderSize.Width - x, RenderSize.Height - lineLength)));
pathGeometry.AddGeometry(newLineGeometry(newPoint(RenderSize.Width, RenderSize.Height - x),newPoint(RenderSize.Width - lineLength - x, RenderSize.Height - x)));
drawingContext.DrawGeometry(Brushes.Transparent, selectedBorderPen, pathGeometry);
}
base.OnRender(drawingContext);
}
#endregion
}
}
// AdornerPanel.cs
using
System;using
System.Collections.Generic;using
System.Text;using
System.Windows.Controls;using
System.Windows.Controls.Primitives;using
System.Windows.Media;using
System.Windows;using
System.Diagnostics;using
System.Windows.Documents;namespace
AdornerRendering{
publicclassAdornerPanel :Panel
{
#region
ConstspublicstaticreadonlySize Layout1x1 =newSize(1, 1);
publicstaticreadonlySize Layout4x4 =newSize(4, 4);
publicstaticreadonlySize Layout8x8 =newSize(8, 8);
publicstaticreadonlySize Layout16x16 =newSize(16, 16);
publicstaticreadonlySize Layout32x32 =newSize(32, 32);
#endregion
#region
Dependency Properties#region
Layout Property///Identifies the Layout dependency property
publicstaticreadonlyDependencyProperty LayoutProperty =
DependencyProperty.Register("Layout",typeof(Size),typeof(AdornerPanel),
newFrameworkPropertyMetadata(Layout1x1,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.AffectsArrange |
FrameworkPropertyMetadataOptions.AffectsMeasure, OnLayoutChanged));
staticvoid OnLayoutChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
AdornerPanel panel = dasAdornerPanel;
}
publicSize Layout
{
get {return (Size)GetValue(LayoutProperty); }
set { SetValue(LayoutProperty,value); }
}
#endregion
#endregion
#region
OverridesprotectedoverrideSize MeasureOverride(Size availableSize)
{
Size childSize =newSize(
availableSize.Width / Layout.Width,
availableSize.Height / Layout.Height);
foreach (UIElement childin InternalChildren)
{
child.Measure(childSize);
}
return availableSize;
}
protectedoverrideSize ArrangeOverride(Size finalSize)
{
int childNumber = 0;
Size childSize =newSize(
finalSize.Width / Layout.Width,
finalSize.Height / Layout.Height);
foreach (UIElement childin InternalChildren)
{
Point childPosition =newPoint(
childSize.Width * (childNumber % (int)Layout.Width),
childSize.Height * (childNumber / (int)Layout.Width));
child.Arrange(newRect(childPosition, childSize));
++childNumber;
}
return finalSize;
}
protectedoverridevoid OnVisualChildrenChanged(DependencyObject visualAdded,DependencyObject visualRemoved)
{
UIElement element = visualAddedasUIElement;
if (visualAdded !=null)
{
AdornerLayer layer =AdornerLayer.GetAdornerLayer(element);
#region
AssertDebug.Assert(layer !=null,string.Format("Make sure that {0} is decorated with an AdornerDecorator", visualAdded));
#endregion
layer.Add(newSelectionAdorner(element));
}
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
}
#endregion
}
}
<Windowx:Class="AdornerRendering.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:AdornerRendering"Title="AdornerRendering"Height="380"Width="300">
Grid><
<Grid.RowDefinitions>
<RowDefinitionHeight="80"/>
<RowDefinition />
</Grid.RowDefinitions>
<WrapPanel>
<ButtonContent="Add"Click="buttonAdd_Click" />
<TextBoxx:Name="textBoxCount"Text="1"Width="50" />
<ButtonContent="Remove Selected"Click="buttonRemove_Click" />
<ButtonContent="1x1"Click="buttonLayout_Click"
Tag="{x:Static local:AdornerPanel.Layout1x1}"/>
<ButtonContent="4x4"Click="buttonLayout_Click"
Tag="{x:Static local:AdornerPanel.Layout4x4}"/>
<ButtonContent="8x8"Click="buttonLayout_Click"
Tag="{x:Static local:AdornerPanel.Layout8x8}"/>
<ButtonContent="16x16"Click="buttonLayout_Click"
Tag="{x:Static local:AdornerPanel.Layout16x16}"/>
</< FONT><WrapPanel>
<AdornerDecoratorGrid.Row="1">
<local:AdornerPanelx:Name="_panel" />
</< FONT></AdornerDecorator>
</< FONT></Grid>
</< FONT></Window>
// Window1.xaml.cs
using
System;using
System.Collections.Generic;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.Shapes;namespace
AdornerRendering{
publicpartialclassWindow1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
}
void buttonAdd_Click(object sender,RoutedEventArgs e)
{
int count =int.Parse(textBoxCount.Text);
for (int i = 0; i < count; i++)
{
TextBlock textBlock =newTextBlock(newRun("Item " + (i + 1).ToString()));
_panel.Children.Add(textBlock);
}
}
void buttonRemove_Click(object sender,RoutedEventArgs e)
{
}
void buttonLayout_Click(object sender,RoutedEventArgs e)
{
Button button = senderasButton;
_panel.Layout = (Size)button.Tag;
}
}
}
<Applicationx:Class="AdornerRendering.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"StartupUri="Window1.xaml"></Application>
// App.xaml.cs
using
System;using
System.Windows;using
System.Data;using
System.Xml;using
System.Configuration;namespace
AdornerRendering{
///<summary>
/// Interaction logic for App.xaml
///</summary>
publicpartialclassApp : System.Windows.Application
{
}
}

