Positioning of Windows Form Application - winforms

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

Related

Retrieve WP system tray (notification area) height

For some control layout calculations, I need to know the height of the notification area. Sure, I know that it equals 32 pixels in portrait mode in WP 7/8/8.1, but it's not a good idea to hard code this value for the future releases of the OS. How can I retrieve this value on-the-fly in a Silverlight app?
You cant get Height of notification area by Code.
its Standards are Pre-Defined.
System Tray is the small tiny bar across the top of the Phone screen. It displays in Portrait mode. When your application is set in Portrait mode, the height of the System Tray becomes 32 pixel and when the application is set in Landscape mode, the width of the System Tray becomes 72 pixel. This is as per the UI Design Guidelines and Interaction Guideline of Windows Phone 7.
You can get more information here about what is accessible
double contentScaleFactor = (double)Application.Current.Host.Content.ScaleFactor / 100;
double systemTrayHeight = 32 / contentScaleFactor;
Or 72 for landscape orientation. Phones like the Lumia 1520 scale the app content up, so you have to adjust for it.
Found a workaround. We can determine the vertical offset for the main layout root control (generally a Grid), and it will be the height of the system tray:
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
GeneralTransform gt = LayoutRoot.TransformToVisual(Application.Current.RootVisual as UIElement);
Point offset = gt.Transform(new Point(0, 0));
double systemTrayHeight = offset.Y;
}

WPF TouchDevice get absolute coordinates

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 to make label transparent without any flickering at load time

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

Form height problem when FormBorderStyle is NONE

I have a borderless form (FormBorderStyle = None) with the height of 23 pixels (set in the designer)
When .NET draws my form at runtime - it draws it 38 pixels high (it adds the height of a title-bar for some reason).
MessageBox.Show(this.Height.ToString()); //this shows 38!! why?
To work it around I have to set "Height = 23;" in the Form_Load event.
private void MyForm_Load(object sender, EventArgs e)
{
this.Height = 23; //workaround. wtf??
}
You can try this yourself in Visual Studio 2010 (Winforms App, target Framework - 2.0).
Wtf?
Yeah, it is a bug, of sorts. Note how in the designer you set the size of the form with the Width and Height properties. Those properties include the size of the borders and the title bar. That's a problem however, your form may run on a machine where the user has increased, say, the title bar font size. That then would reduce the size of the window's client area. Or in other words, the form's ClientSize property would change on that machine. Leaving less room for the controls and messing up the design of your form pretty badly.
There's code inside the Form class that runs after the Handle is created, right before the Load event runs. It recalculates the Size of the form, using the same ClientSize you had on your machine. Now everything is good, the Height of the form won't match the one you set in the designer but the form otherwise looks the same and the layout of the controls is identical.
That same code also ensures that the window doesn't get too small. And that's where it falls over, it doesn't pay enough attention to the FormBorderStyle property. Clipping the height to the title bar size plus the client area height, as you found out. It also prevents the form getting too narrow, trying to make sure that the icon and min/max/close buttons are always visible. Even if you don't have any.
The workaround is to change the ClientSize after this code runs, the OnLoad override or Load event handler is the right place for that. Beware that if you hard-code the form size like this then you should also set the AutoScaleMode property to None. Make sure that this doesn't cause trouble on a machine that has a different DPI setting.

WPF Window with Style=None cover taskbar when Maximised after app initialization

I want to achieve the same effect as Windows Media Player or Browser based Flash players which take up the ENTIRE (not even the taskbar is visible) real estate when maximized.
This works fine if the WindowState is set to Maximized and the WindowStyle is set to None in XAML so the app is started in that state. Problem is I want to start the app in a bordered window and when the user chooses, maximize as specified above. In the StateChanged handler I check for Maximized state and if this is the case I set the WindowStyle to None. This has the effect of maximizing the window but NOT covering the taskbar. The following code will make this work as I want but its a hack and I'd like to clean it up:
if (WindowState == WindowState.Maximized)
{
m_videoWindow.Maximize();
WindowStyle = WindowStyle.None;
//the following makes this work but I would like to clean it up
Hide();
Show();
}
EDIT This (from 2006 when still in CTP) mentions the problem and someone from MS states they hope to improve full screen support in the next version, have these improvements been made?
This article explains it all: Maximizing window (with WindowStyle=None) considering Taskbar.
Also worth checking out: Custom Window Chrome in WPF.
Edit: Now new, is the WPF Shell Integration Library that allows complete restyle of the window chrome without the headaches of reimplementing move, resizing, etc.
Edit 2015: Shell Integration Library is now integrated in WPF and MS retired the code
I found I could maximize to full screen (covering the taskbar) by setting the properties when creating the window (in xaml), but was not able to switch back and forth after creation. After some experimenting, I found the order the properties are set seems to matter:
public bool IsFullscreen
{
get
{
return WindowState == System.Windows.WindowState.Maximized
&& ResizeMode == System.Windows.ResizeMode.NoResize
&& WindowStyle== System.Windows.WindowStyle.None;
}
set
{
if ( value )
{
ResizeMode = System.Windows.ResizeMode.NoResize;
WindowStyle = System.Windows.WindowStyle.None;
WindowState = System.Windows.WindowState.Maximized;
}
else
{
ResizeMode = System.Windows.ResizeMode.CanResize;
WindowStyle = System.Windows.WindowStyle.SingleBorderWindow;
WindowState = System.Windows.WindowState.Normal;
}
}
}
Note that WindowState comes last in the setter.
To get this to properly work in my WPF/.NET 4.0 application I am calling this function whenever I enter or exit full screen mode:
private static void RefreshWindowVisibility(Window window)
{
if (window.OriginalWindowState == WindowState.Maximized)
{
window.Hide();
window.Show();
window.BringIntoView();
}
}
There is a flicker associated with this method, but it seems the same flicker exists when going to full screen mode on Chrome. Internet Explorer seems to take a different approach.
I don't know if this is ok for you, but you can resize the window to have the same size than the working area (that is, in most cases, all the screen except the taskbar) and locate it at 0,0 (top-left corner):
Width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
Height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
Left = 0;
Top = 0;
The exact definition for the WorkingArea property (from MSDN) is:
Gets the working area of the display. The working area is the desktop area of the display, excluding taskbars, docked windows, and docked tool bars.
Hope it helps

Resources