In Windows Forms, how can I get the screen on which a Window was maximized on? I have a lot of problems finding that screen when I maximize a Form on my right screen.
Currently I have been iterating over all the screens with a IntersectsWith check. But if your windows is positioned on both the screens before maximizing, both screens will intersect with the RestoreBounds of the window. As a result I will still not know on which screen the window was maximized on...
If I use the DesktopBounds, then they both screens also intersect with them. This is very strange as those bounds are really bounds of a maximized Form on my right screen (1912, 87, 1456, 916). How is it possible that my left screen intersects with those bounds?
Apparently my left screen has a resolution of 1920x1080, so the question really is why the DesktopBound.Left value is 1912 when maximized on my right screen? Shouldn't it be 1921?
Code snippet:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (var screen in Screen.AllScreens)
{
if (screen.Bounds.IntersectsWith(this.DesktopBounds))
{
//Found screen
}
}
}
to get the whole picture, we save the bounds and windowstate of the Form when it is closed. When it is opened again, it is restored to the same bounds and windowstate.
You could just use Screen.FromControl(this) to get the screen where the form is positioned... however you should check if it's maximized beforehand, else that'll get you the screen where the largest part of the form is (then again, that'd be the screen where the form would maximize to in case you maximized it).
Related
In my scenario I have a window which I want to use to display on two different ways. One way when the window has WindowState = WindowState.Normal; and the other way where the window has Normal or Maximised state.
I want to save the Size and Position of these two window modes so for the user it would seem like two separate windows.
I have two different issues around this.
1) When I initialize the window after Show() has been called, there is a small flicker which on slower machines isn't such a short flicker. In order to fix this I wanted to set up the window while it is hidden like so:
((SecondWindowViewModel)this.DataContext).LoadWindowPosition(mode);
this.Show();
if I do this an even worst problem comes up
2)In this case window 1 which is in normal mode has some random height set on drag after window 2 has been closed in Maximized mode.
I've created a sample application what you can find here, where you can see the exact problem, I've also written down the steps to reproduce as well.
EDIT
Implemented Maxims Changes and removed unnecessary references
Haven't had yet the time to completely solve your issue, but one issue you have in your code is that you do not set the window state accordingly to your mode. In SecondWindow.xaml.cs, your code should look like this:
if (mode == WindowViewMode.Normal)
{
WindowState = WindowState.Normal;
}
else
{
WindowState = WindowState.Maximized;
}
if (this.IsVisible)
{
this.Hide();
}
else
{
((SecondWindowViewModel)this.DataContext).LoadWindowPosition(mode);
this.Show();
}
Still need to take a look at the problems your LoadWindowPosition is causing.
I try to create a window, that can be moves or resized via multi-touch gestures. I tried it this way. I captures the TouchDown-Event of the window and saved all active TouchDevices in a List, to know which TouchDevices are active. I catch updated and deactivated event of the TouchDevices to know when they are moved and when they are deactivated. I save the Left and Top Property of the Window and the position where the TouchDevice started and everytime the Updated event is called I move the Window to the new Position relative to the new position of the TouchDevice. This works if I move the finger. But if I don't move the finger (or just very little) the window suddenly began shaking (moving chaotically) and then soon disappears to a position outside of the screen.
I think the problem here is, that the function "GetTouchPoint" of the TouchDevice only give relative coordinates related to the window (even if I set the parameter null instead if the window reference). And because the Window moves the relative position of the TouchDevice (that doesn't move) changes too. So I did a research but wasn't able to find a way to determine the screen coordinates of the touch device.
So I hope anyone can help me how to get the absolute coordinates of the TouchDevice. Or can help me find another way to "DragMove" the window with touch.(I tried DragMove, but that only works for mouse clicks, not TouchDowns) Also I like to resize the window when two Touch Devices are active and therefor I also need absolute coordinates because otherwise same effect happens.
I ran into this issue because my taskbar is on the right edge of the screen, effectively pushing the maximized window to the right. This issue also arises when the application's window is not maximized, and floating somewhere on the screen.
Here is an extension method that fixes the coordinates based on the application window's position.
public static Point FixCoordinates(this Point point)
{
var left = Application.Current.MainWindow.Left;
var top = Application.Current.MainWindow.Top;
return new Point(point.X + left, point.Y + top);
}
You may want to pass in a window that hosts your touched control as a parameter. In my case it is application's main window.
Also, since you tagged the question with "multi-touch", here is a method which averages multiple touch coordinates:
public static Point GetAverage(this IEnumerable<Point> points)
{
var averageX = points.Average(p => p.X);
var averageY = points.Average(p => p.Y);
return new Point(averageX, averageY);
}
And I use it in the code like this:
private void TouchAdornment_TouchDown(object sender, TouchEventArgs e)
{
var touchPosition = (sender as UIElement).TouchesOver.Select(t => t.GetTouchPoint(null).Position).GetAverage().FixCoordinates();
}
How do I code the start location of my winform app such that it always starts in the bottom right hand corner of the screen. As using x and y coordinate only affects one particular screen resolution, on a smaller or larger screen the winform would not appear in the desired location.
Thanks!
You have to do this in the OnLoad() method/event, one of the few real reasons to use it. The form's actual size won't be the designed size because the user might have changed preferences like the window caption height or the form might be rescaled due to a different video DPI setting. This is all sorted out when OnLoad() starts running.
Make it look like this:
protected override void OnLoad(EventArgs e) {
var scr = Screen.FromPoint(this.Location);
this.Left = scr.WorkingArea.Right - this.Width;
this.Top = scr.WorkingArea.Bottom - this.Height;
base.OnLoad(e);
}
Check this on MSDN:
Setting the Screen Location of Windows Forms
Regards
In Silverlight 4, is there a way that whenever you page down a ScrollViewer (i.e click the scroll bar in the area adjacent to the thumb) whatever item is at the top is completely visible. I still need it to scroll smoothly when the thumb is dragged or the mouse wheel is used.
My client doesn't like that an item is cut in half when he pages down the list because it is cut in half both when its at the top and when its at the bottom. I suggested some sort of integral scroll, and he didn't like it. He wants it to still scroll smoothly unless paging up or down.
Edits
Here's the catch. The items are not the same size. So I have to detect the item that is at the top of the scroll viewer and Scroll it into view. Is there an easy way to do this?
The first thing you need to do is dig out the vertical scroll bar from the internals of the ScrollViewer. You can do this with the help of VisualTreeHelper. There are a number of little chunks of code in various blogs the make its use even easier. I recommend this VisualTreeEnumeration (but I would wouldn't I). With that extensions class in place you can get the vertical scroll bar with:
ScrolBar vertSB = someScrollViewer.Descendents()
.OfType<ScrollBar>()
.FirstOrDefault(sb => sb.Name = "VerticalScrollBar");
Now you can attach to is Scroll event and determine the type of scroll that occured like this:
vertSB.Scroll += (s, args) =>
{
if (args.ScrollEventType == ScrollEventType.LargeDecrement
|| args.ScrollEventType == ScrollEventType.LargeIncrement)
{
// using args.NewValue determine the correct Integral value and assign
// using someScrollViewer.ScrollToVerticalOffset
}
};
I have a panel and on that I've a picturebox. There are around 20 labels that I've to show in the panel. I want the background of Label to be transparent ie the image in picturebox is shown and the label displays only the text.
Now since labels do not exhibit true transparency I made the labels child of picturebox
this.lbl1.Parent = pictureBox1;
This has solved my immediate problem but now when the form loads, all the labels take a while to become visible and do so one at a time. I'd appreciate if you guys can give some solution for this.
Thanks in advance
The standard cure for flicker is double-buffering. But that cannot solve this kind of flicker. It is a different kind, caused by having multiple windows overlapping each other. Each label is its own window. When the form needs to paint itself, it draws its background leaving holes for the child windows. Each child window then takes a turn drawing itself. And their child windows draw themselves next. Etcetera.
This becomes noticeable when one control takes a while to draw, no doubt your picture box. Especially when it displays a large image that needs to be resized. The holes for the child windows stay unpainted while the picture box draws. They have a white background, black when you use the form's TransparencyKey or Opacity property. This can contrast badly with the image in your picture box, that effect is perceived by the user as flicker.
One immediate cure is to not use controls so you don't pay for their window. A Label is very convenient but it is a massive waste of system resources to burn up a window just to display a string. You can simply implement the picture box' Paint event and draw the strings with TextRenderer.DrawText(). PictureBox has double-buffering turned on by default so the image as well as the text is drawn completely smoothly, no more flicker. The obvious disadvantage is that you lose the convenience of point-and-click, you have to write code.
There are other fixes possible. One of them is to prevent the picture box from leaving holes for the child windows. It will draw the entire image, the labels pop on top of them. That's still flicker but not nearly as noticeable. Add a new class to your project and paste this code:
using System;
using System.Windows.Forms;
internal class MyPictureBox : PictureBox {
protected override CreateParams CreateParams {
get {
var parms = base.CreateParams;
parms.Style &= ~0x02000000; // Turn off WS_CLIPCHILDREN
return parms;
}
}
}
Compile and drop the new picture box control from the top of the toolbox onto your form.
Yet another possible workaround is to make the form and all of its children double-buffered. This doesn't speed up the painting at all but all of the windows get rendered into a memory buffer, the result is blitted to the screen. You'll notice a delay but the window suddenly pops on the screen. This is called compositing. Winforms doesn't support this directly since it can have side-effects but it is easy to enable. Paste this code into your form class:
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
Supported by XP and later. Watch out for painting artifacts.
or you can ditch the labels and draw the text yourself:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
TextRenderer.DrawText(e.Graphics, "Label1", SystemFonts.DefaultFont,
new Point(10, 10), Color.Black, Color.Empty);
}
The label does not support transparency, you must create your own unique custom control, you can see these code examples.
http://www.codeproject.com/KB/dotnet/transparent_controls_net.aspx http://www.codeproject.com/KB/vb/uLabelX.aspx
Bye