So I finally have found the solution: attached property. I created an attach property and on the property change callback method subscribed on the AdornerDecorator.Loaded event. In the method you can check the real position and change properties if needed.
[Sample code-snippet, in the real source it is more outsourced and rechecked due code-specific issues]
private static void DecoratorLoaded(object obj, RoutedEventArgs e)
{
var decorator = obj as Decorator;
if (decorator != null && decorator.IsVisible)
{
// get the position
Point renderedLocation = decorator.TranslatePoint(new Point(0, 0), Application.Current.MainWindow);
if (renderedLocation != new Point(0, 0))
{
// check width
var maxAllowedWidth = Application.Current.MainWindow.ActualWidth - renderedLocation.X - 40;
decorator.SetValue(FrameworkElement.MaxWidthProperty, maxAllowedWidth);
// check place above the control
var isEnoughPlaceAbove = renderedLocation.Y > decorator.ActualHeight + 10;
decorator.SetValue(Grid.RowProperty, isEnoughPlaceAbove ? 0 : 2);
// invalidate to re-render
decorator.InvalidateVisual();
}
}
}
You need to use Loaded
event to make sure the renderLocation will deliver you the actual position and not something else (e.g zero or some relative positions).
Finally you need to attach the attached property to the decorator in XAML:
<AdornerDecorator Behaviors:AdornerPositionCalculator.AllowDynamicPosition="True">
<!-- custom style here -->
</AdornerDecorator>