I developed a Winforms application that has a Toolbar. The last element in the toolbar is a ToolStripDropDownButton with some items.
I needed this button to be shown apart from all other toolbar buttons, so I set the Alignment property to right.
In my PC this works perfectly, however, when I moved the whole Visual Studio project to my notebook and then ran the application, the menu items are not shown when I click the button, however, the dropdown button changes color indicating that it was selected.
At design time, items are shown correctly.
What is happening here and is it possible to solve it? At the moment, I set the button alignment to left, so that it is shown together with other toolbar buttons.
Thanks
Jaime
Check your DPI settings on your notebook. It is likely changing the size and padding of your elements. You can get around this by checking for the system's DPI value and calculating sizes of controls based on that.
var graphics = this.CreateGraphics();
var dpiX = graphics.DpiX / 96d; // Default DPI
var dpiY = graphics.DpiY / 96d; // Default DPI
myToolbar.Width = myWidth * dpiX;
myToolbar.Height= myHeight * dpiY;
Related
I use an ElementHost control to integrate Wpf into a winforms application. I have created a "kind" of step by step set of screens similar to a wizard with next and back buttons among others.
Windows Form ---- ElementHost ---- Wpf
When I go through the different screens, i am not closing and opening a new window again, instead I simply keep the same window already opened and I change only its content. The problem of this is that the elementHost is not resizing to fit its content height, neither if the content height is decreased or increased (caused by for example an expander collapse or expand or some other control). Instead the elementhost keeps always the height that was taken the first time it was open.
The elementhost has set its properties correctly, AutoSize = true and Dock to Fill. And the Windows Form where the elementhost is, also has AutoSize set to true correctly.
So in order elementhost resizes, what I do is to "force" the elementhost to resize by doing the following on each transition between screens:
System.Drawing.Size eh = myElementHost.Size;
ElementHost.SuspendLayout();
ElementHost.AutoSize = false;
ElementHost.Size = new System.Drawing.Size(eh.Width, eh.Height);
ElementHost.AutoSize = true;
ElementHost.ResumeLayout(true);
This trick causes elementhost to resize to fit its content height but.... it is causing flickering.... also for example, each time I click on the toggle button of an expander to collapse or expand it or do something in the content that cause it to modify the content height, I need to call above piece of code to force elementhost to resize correctly to fit its content height but again, it is causing flickering, so how can avoid flickering in this particular use case?
I have a simple task that I want to accomplish: Have a WPF window launch with a Horizontal Alignment that is stretched to the total width of the current screen. I want to achieve a kind of custom Overlay MessageBox (I dont want to use third party controls such as MahApps), I am not using any third party references for this.
Please see what I have achieved so far (Not sure if the image will show, the link is http://imgur.com/e27DyNJ):
I have tried setting the width with a Controller object that I wrote which works, that basically sets the Width, Height, Left and Top to the width of the primary monitor. Downside is the window then pops up on the primary screen, not on the screen that is currently in use.
As far as I know, WPF doesn't have any multi-screen functions. You could PInvoke some native Multiple Display Monitor Functions, wrap them in a managed class and utilize them in that regard, though.
As a workaround, I have done the following:
var screen = System.Windows.Forms.Screen.FromRectangle(new System.Drawing.Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height));
window.Width = screen.WorkingArea.Width;
window.Left = screen.WorkingArea.Left;
where window is the instance of my window I want to resize.
This works with the current screen the window was opened on.
I'm using the wpf notifyicon (http://www.hardcodet.net/wpf-notifyicon)
When my laptop is at 100% dpi scaling, the left side of the context menu is centred on the tray icon, as expected.
When the laptop isn't at 100%, the context menu is pushed to the far right.
On high resolution laptop displays, 100% scaling is not the default.
Wherever my tray icon is positioned, that is, however far from the clock, the menu always pops up over the clock, as far to the bottom-right of the screen as is possible while remaining visible.
Note: I'm testing on a default installation of Windows 8.1. Also, the NotifyIcon that I'm using is the one that is generally recommended for anyone attempting tray functionality in WPF.
To reproduce: the problem exists in the windowless sample provided by hardcodet. I'm using wpf NotifyIcon without a window, and can reproduce easily in code or xaml. In fact, I cannot stop reproducing it. It occurs when dpi scaling is turned on, i.e. when a 1080p display is actually showing a lesser resolution, which is what windows does to stop applications having text too tiny to read.
Any ideas about how I can make the context menu appear in the expected place regardless of dpi?
Screen shots as suggested by kennyzx:
good behaviour. the m on red background (MEGAsync) has just been right-clicked
bad behaviour. the green tick, my notifyicon, has just been right-clicked and the menu appears over the clock
!good behaviour. the m on red background (MEGAsync) has just been right-clicked
!bad behaviour. the green tick, my notifyicon, has just been right-clicked and the menu appears over the clock
and some code:
var n = new TaskbarIcon();
n.Icon=new System.Drawing.Icon(#"C:\window - 64 - tick.ico");
n.ContextMenu = new System.Windows.Controls.ContextMenu();
n.ContextMenu.Items.Add(new System.Windows.Controls.MenuItem {Header="E_xit" });
Found the solution here: http://www.codeproject.com/Messages/4929452/Problem-with-context-menu-position.aspx
It is, with thanks to codeproject user Igorious:
Get the code for Wpf Notifyicon (http://www.hardcodet.net/wpf-notifyicon)).
In Hardcodet.Wpf.TaskbarNotification.TaskbarIcon.ShowContextMenu()
replace
ContextMenu.HorizontalOffset = cursorPosition.X;
ContextMenu.VerticalOffset = cursorPosition.Y;
with
var g = Graphics.FromHwnd(IntPtr.Zero);
var scaleX = g.DpiX / 96.0;
var scaleY = g.DpiY / 96.0;
ContextMenu.HorizontalOffset = cursorPosition.X / scaleX;
ContextMenu.VerticalOffset = cursorPosition.Y / scaleY;
Explanation (thanks to codeproject user yachting):
It's needed because WinApi.GetPhysicalCursorPos return the mouse position in pixel,
but WPF's measurement unit is device independent pixel (by definition, it's 1/96 inch)
You need to adjust the return value of GetPhysicalCursorPos by DPI (dots per inch) setting,
otherwise the position of the context menu will be incorrect if users set DPI other than the default 96.
I use two displays with different resolutions on my development machine. The display with a smaller resolution is configured as primary display. If I maximize my WPF application on the secondary display and show a popup control at the bottom it appears repositioned:
I guess, the framework uses the lower resolution of the primary display to check if the popup window has to be repositioned. Doesn't the WPF framework check for the current display resolution or do I have to configure this myself?
For repositioning popup control on two monitor, better to set Popup control Horizontal and Vertical offset based on PointToScreen property of MainWindow
var mousePosition = Mouse.GetPosition(Application.Current.MainWindow);
var pointToScreen = Application.Current.MainWindow.PointToScreen(mousePosition);
_popup.HorizontalOffset = pointToScreen.X;
_popup.VerticalOffset = pointToScreen.Y;
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.