WPF - Set dialog window position relative to main window? - wpf

I'm just creating my own AboutBox and I'm calling it using Window.ShowDialog()
How do I get it to position relative to the main window, i.e. 20px from the top and centered?

You can simply use the Window.Left and Window.Top properties. Read them from your main window and assign the values (plus 20 px or whatever) to the AboutBox before calling the ShowDialog() method.
AboutBox dialog = new AboutBox();
dialog.Top = mainWindow.Top + 20;
To have it centered, you can also simply use the WindowStartupLocation property. Set this to WindowStartupLocation.CenterOwner
AboutBox dialog = new AboutBox();
dialog.Owner = Application.Current.MainWindow; // We must also set the owner for this to work.
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
If you want it to be centered horizontally, but not vertically (i.e. fixed vertical location), you will have to do that in an EventHandler after the AboutBox has been loaded because you will need to calculate the horizontal position depending on the Width of the AboutBox, and this is only known after it has been loaded.
protected override void OnInitialized(...)
{
this.Left = this.Owner.Left + (this.Owner.Width - this.ActualWidth) / 2;
this.Top = this.Owner.Top + 20;
}
gehho.

I would go the manual way, instead of count on WPF to make the calculation for me..
System.Windows.Point positionFromScreen = this.ABC.PointToScreen(new System.Windows.Point(0, 0));
PresentationSource source = PresentationSource.FromVisual(this);
System.Windows.Point targetPoints = source.CompositionTarget.TransformFromDevice.Transform(positionFromScreen);
AboutBox.Top = targetPoints.Y - this.ABC.ActualHeight + 15;
AboutBox.Left = targetPoints.X - 55;
Where ABC is some UIElement within the parent window (could be Owner if you like..) , And could also be the window itself (top left point)..
Good luck

Related

How to make WPF Window cross 4 screens?

I have Four monitors with my PC,Is there any way to make a WPF window display cross four screens and maximized?
I'd like just to complete Mark's answer. Actually the answer is no you can't and it is a windows limitation that only allows to maximize on one screen. However you can have a non maximized window stretched across multiple screens.
A more WPF approach would be something like this:
this.WindowState = WindowState.Normal;
this.Top = SystemParameters.VirtualScreenTop;
this.Left = SystemParameters.VirtualScreenLeft;
this.Width = SystemParameters.VirtualScreenWidth;
this.Height = SystemParameters.VirtualScreenHeight;
However I don't really know how it will behave when stretching across windows arranged in T or L shape.
Yes, add a project reference to System.Windows.Forms and then add this to your MainWindow class:
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
// get extents of all windows
var left = System.Windows.Forms.Screen.AllScreens.Min(screen => screen.Bounds.X);
var top = System.Windows.Forms.Screen.AllScreens.Min(screen => screen.Bounds.Y);
var right = System.Windows.Forms.Screen.AllScreens.Max(screen => screen.Bounds.X + screen.Bounds.Width);
var bottom = System.Windows.Forms.Screen.AllScreens.Max(screen => screen.Bounds.Y + screen.Bounds.Height);
var width = right - left;
var height = bottom - top;
// resize main window accordingly
this.WindowState = WindowState.Normal;
this.Top = top;
this.Left = left;
this.Width = width;
this.Height = height;
}

WPF - How to work out how much of a canvas background image is cropped?

I have a canvas with a background image:
var bi = new BitmapImage(new Uri(imgLocFull));
var ib = new ImageBrush(bi) {Stretch = Stretch.UniformToFill};
MyCanvas.Background = ib;
I am overlaying various shapes on the image, and want the position of the shapes relative to the background image to be fixed.
If my application window is resized, the amount of the image that is cropped, horizontally and vertically, changes, and when my shapes are redrawn, they do not appear in the same position on the background image.
How can I determine how much of the image has been cropped (to apply an adjustment factor to the overlaid objects' positions?) Or is there a better way of fixing the location of a shape relative to the background image?
Here is my present drawing code:
var l = new Ellipse();
var scb = new SolidColorBrush();
scb.Color = Color.FromRgb(rCol, gCol, bCol);
l.Fill = scb;
l.StrokeThickness = 0;
l.Width = 3;
l.Height = 3;
Canvas.SetBottom(l, point.Y); // * clipping factor here?
Canvas.SetLeft(l, point.X); // * clipping factor here?
MyCanvas.Children.Add(l);
EDIT: Further Clarification
Here's a concrete example of what I am trying to achieve. My image is an aerial photograph, and I want to mark a particular geographical feature (with, say, an ellipse.)
When the window is resized, the ellipse doesn't stay on the feature, it stays relative to the left and top of the canvas.
I can get it closer to the right place by moving it using a factor (newx = newheight/oldheight * oldx) but this doesn't quite work because of the UniformToFill stretch mode, which sees some of the image clipped off the canvas.
The Top and Left of the Canvas are 'anchored', while the Bottom and Right move when resizing... try setting the Canvas.Top Attached Property instead, along with the Canvas.Left Attached Property as you are:
var l = new Ellipse();
var scb = new SolidColorBrush();
scb.Color = Color.FromRgb(rCol, gCol, bCol);
l.Fill = scb;
l.StrokeThickness = 0;
l.Width = 3;
l.Height = 3;
Canvas.SetTop(l, point.Y); // * clipping factor here?
Canvas.SetLeft(l, point.X); // * clipping factor here?
MyCanvas.Children.Add(l);
UPDATE >>>
You asked Or is there a better way of fixing the location of a shape relative to the background image?
I answered this question, so I don't understand why you would need to do anything else... your objects will not move when the screen in resized *if you only set the Grid.Top and Grid.Left properties.

Unable to set a property after its animation in WPF

I used this code to animation my window:
winLogin login = new winLogin();
login.Owner = this;
login.Show();
DoubleAnimation da = new DoubleAnimation();
da.From = 0;
da.To = this.Left + ((this.Width - login.Width) / 2);
da.AutoReverse = false;
da.Duration = new Duration(TimeSpan.FromSeconds(0.1));
login.BeginAnimation(Window.LeftProperty, da);
Problem is that whenever i set the Left property of this window(after the animation), it goes crazy.
I used this code to align the child windows to be always on the center but the Left property of the windows on which i used an animation cannot be properly changed.
private void Window_LocationChanged(object sender, EventArgs e)
{
foreach (Window win in this.OwnedWindows)
{
win.Top = this.Top + ((this.Height - win.Height) / 2);
win.Left = this.Left + ((this.Width - win.Width) / 2);
}
}
First of all, when you set an animation you should always remove the potential previous animation of that property:
login.BeginAnimation(Window.LeftProperty, null);
login.BeginAnimation(Window.LeftProperty, da);
If you don't so this you will get a memory leak and probably some other undesired behavior.
Also due to the DependencyProperty precedence you can not set a value on a DependecyProperty that has an active animation, wich is the case in your animation because its FillBehavior is set to HoldEnd (the default). Again you would have to remove the animation first.

Silverlight programmatically binding from C# code

I have a Canvas and a custom control called BasicShape
After I add two BasicShape controls on the Canvas, I want programatically to connect them with a Line and I want to do this using the Binding class.
I want to connect the Bottom side of first shape with the Top side of the second one.
Initially i tried to connect only the X1 property of the Line with the Canvas.Left attached property of the fisrt BasicShape but this doesn't work. Line X1 property is not updated when I change the Canvas.SetLeft(basicShape1) value
BasicShape bs1 = canvas.Children[0] as BasicShape;
BasicShape bs2 = canvas.Children[1] as BasicShape;
Line line = new Line();
line.StrokeThickness = 1;
line.Stroke = new SolidColorBrush(Colors.Red);
line.X1 = 100;
line.Y1 = 100;
line.X2 = 200;
line.Y2 = 200;
canvas.Children.Add(line);
Binding b = new Binding("AnyName");
b.Source = bs1;
b.Path = new PropertyPath(Canvas.LeftProperty);
line.SetBinding(Line.X1Property, b);
I'm trying to create a simple UML diagram like this one
alt text http://www.invariant-corp.com/omechron/images/uml_diagram.gif
I just did it other way, without binding
This will be a permanent link
http://calciusorin.com/SilverlightDiagrams/
I decided to manually update all lines on shape Location or Size changed
private void basicShape_BasicShapeLocationSizeChangedEvent(BasicShape sender)
{
foreach (CustomLine customLine in lines)
{
if (customLine.StartFromShape(sender))
{
Point point = sender.GetLinePoint(customLine.GetStartSide());
customLine.SetStartPoint(point);
}
if (customLine.EndInShape(sender))
{
Point point = sender.GetLinePoint(customLine.GetEndSide());
customLine.SetEndPoint(point);
}
}
}
I am sure that the Binding solution is more elegant. Anyone interested in my solution, with SL Controls that can be resized, connected with lines, just contact me.

How to force ActualWidth and ActualHeight to update (silverlight)

I a grid on my silverlight control, I am programatically adding a canvas, and in the canvas I am loading and displaying Image.
I'm also adding a rotation to the canvas. The problem is that by default the CenterX and CenterY of the rotation is the top left of the canvas. What I want is the rotation to happen around the centre of the canvas.
To do this, I've tried setting the CenterX and CenterY of the Rotation to the Images ActualWidth / 2 and ActualHeight / 2, however I've discovered that ActualWidth and ActualHeight are not always populated, at least not right away. How can I force them to get updated?
Even using the DownloadProgress event on the image doesn't seem to guarantee the ActualWidth and ActualHeight are populated, and neither does using this.Dispatcher.BeginInvoke()...
Image imgTest = new Image();
Canvas cnvTest = new Canvas();
Uri uriImage = new Uri("myurl", UriKind.RelativeOrAbsolute);
System.Windows.Media.Imaging.BitmapImage bmpDisplay = new System.Windows.Media.Imaging.BitmapImage(uriImage);
bmpDisplay.DownloadProgress += new EventHandler<System.Windows.Media.Imaging.DownloadProgressEventArgs>(this.GetActualDimensionsAfterDownload);
imgTest.Source = bmpDisplay;
imgTest.Stretch = Stretch.Uniform;
imgTest.HorizontalAlignment = HorizontalAlignment.Center;
imgTest.VerticalAlignment = VerticalAlignment.Center;
cnvTest.Children.Add(imgTest);
this.grdLayout.Children.Add(imgTest);
this.Dispatcher.BeginInvoke(new Action(GetActualDimensions));
To update the ActualWidth and ActualHeight of a FrameworkElement you will have to call UpdateLayout.
Unfortunately, calling updateLayout doesn't always work either depending on your situation.
I've had better luck doing something like:
whateverUIElement.Dispatcher.BeginInvoke(()
{
//code that needs width/height here
}
);
but even that fails too often.
Most reliable method I found is to use DependencyPropertyDescriptor AddValueChanged listeners of ActualWidth and ActualHeight instead of OnLayoutUpdated to get element sizes after rendering
DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(StackPanel));
if (descriptor != null)
{
descriptor.AddValueChanged(uiPanelRoot, DrawPipelines_LayoutUpdated);
}
descriptor = DependencyPropertyDescriptor.FromProperty(ActualHeightProperty, typeof(StackPanel));
if (descriptor != null)
{
descriptor.AddValueChanged(uiPanelRoot, DrawPipelines_LayoutUpdated);
}
void DrawPipelines_LayoutUpdated(object sender, EventArgs e)
{
// Point point1 = elementInstrumentSampleVial.TranslatePoint(
// new Point(11.0, 15.0), uiGridMainInner);
}
Instead of using StackPanel, Grid etc. use base element that you are depending on for relative sizes

Resources