views:

145

answers:

1

I want to position a modal dialog (progress window) at the top right corner of the parent window client area.

This code will put it in the corner of the non-client area, but how do I calculate the offset to the client area?

this.Owner=owner;
this.Left=owner.Left+owner.ActualWidth-Width;
this.Top=owner.Top;

Edit:

I found this 'solution' that works for normal windows:

this.Left=owner.Left+owner.ActualWidth-Width-SystemParameters.ResizeFrameVerticalBorderWidth;
this.Top=owner.Top+SystemParameters.ResizeFrameHorizontalBorderHeight+SystemParameters.WindowCaptionHeight;

This would however fail for windows that have customized borders.

EDIT:

The code should work regardless of the systems DPI setting (e.g. 120 instead of 96).

+1  A: 

As long as your window content is a subclass of UIElement (which is normally the case), you can simply check the area covered by the Content:

Matrix scaling = PresentationSource.FromVisual(windowContent)
                   .CompositionTarget.TransformFromDevice;

UIElement windowContent = owner.Content as UIElement;

Point upperRightRelativeToContent = new Point(
  windowContent.RenderSize.Width + owner.Margin.Right,
  -owner.Margin.Top);

Point upperRightRelativeToScreen =
  windowContent.PointToScreen(upperRightRelativeToContent);

Point upperRightScaled =
  scaling.Transform(upperRightRelativeToScreen);

this.Owner = owner;
this.Left = upperRightScaled.X - this.Width;
this.Top = upperRightScaled.Y;

If you have a strange situation where you want this to work for arbitrary Window.Content, you'll have to search the window's visual tree using VisualTreeHelper.GetChildCount() and VisualTreeHelper.GetChild() until you come to a ContentPresenter whose Content property matches that of the Window, and use its first visual child as "windowContent" in the above code.

Ray Burns
Thanks but this code appears to only work on systems that are set to 96 DPI. Maybe this is a WPF bug but I need it to work on 120 DPI as well.
chris
I forgot to include the scaling using TransformFromDevice. I've added the required code to my answer, so now this will work at any DPI.
Ray Burns
Works great, thanks. I only found an issue when the windowContent has a margin. In that case you also have to adjust upperRightRelativeToContent for ((FrameworkElement)windowContent).Margin.
chris