I try to avoid the XY Problem by saying immediately what I want and then what I get. 😛
So, first of all, I minimize my MainWindow and thoroguh its NotifyIcon ContextMenu I want that my MainWindow reappears.
The problem: the MainWindow doesn't appear/show as Window, but it appears as Icon in the toolbar (see figure 2).
The code:
This is the TrayIcon initializer:
private void InitializeTrayIcon()
{
KyactusTrayIcon = new NotifyIcon();
KyactusTrayIcon.Icon = AppIcon;
KyactusTrayIcon.Visible = true;
KyactusTrayIcon.ContextMenu = new ContextMenu(new []
{
new MenuItem("Chiudi", ExitApplication),
new MenuItem("Mostra", ShowMainWindow),
});
ShowNotification(#"Ciao " + Globals.CurrentUser.Name + #"!", #"Benvenuto su Kyactus");
}
This is the delegate responsible to show the minimized MainWindow (not working at all):
private void ShowMainWindow(object sender, EventArgs e)
{
WindowState = WindowState.Normal;
Topmost = true;
Show();
Activate();
}
This is what happens when the MainWindow is minimized by clicking the [-] button (ie the Hide() method):
private void MainWindow_OnStateChanged(object sender, EventArgs e)
{
switch (this.WindowState)
{
case WindowState.Maximized:
ShowNotification("Bleah!", "Questo è proprio brutto! :(");
break;
case WindowState.Minimized:
Hide();
ShowNotification("Avviso", "L'applicazione è ora minimizzata qui");
break;
case WindowState.Normal:
break;
}
}
Step one. The method MainWindow_OnStateChanged will be invoked when click on [-]:
Step two. The window disappears (ok) and the Tray icon appears (ok). Then I click on 'Mostra' (translated as 'Show') and the ShowMainWindow delegate will be invoked
Step three. This is the final step, that is, what I do not expect. The MainWindos 'lives' as an Icon in the toolbar. But I can't see it as a Window.
Please note that I have not this problem when I close the window by clicking [X] instead of [-]. So, my suspect is the MainWindow's Window.State. I tried to restore it implementing the WindowState.Normal into the ShowMainWindow, but nothing.
Update: if is use WindowState.Maximized in the ShowMainWindow method,
I can see the window again, but it is maximized and this is bad and ugly.
Just change the order of operation when showing the window
private void ShowMainWindow(object sender, EventArgs e)
{
Show();
WindowState = WindowState.Normal;
Topmost = true;
Activate();
}
Simply,create some class-level integer variables and store the height,width and positioning values there.Then use them to get back the size of your window :
int height;
int width;
double left;
double top;
private void MainWindow_SizeChanged
{
height = this.Height;
width = this.Widthl
left = this.Left;
top = this.Top;
}
private void ShowMainWindow(object sender, EventArgs e)
{
this.Height = height;
this.Width = width;
this.Left = left;
this.Top = top;
}
Related
I am trying to send a window to a screen, and place that window in the center of the screen. When the button is clicked, it send / close the window and change button content.
My first issue is I can open and close the Window, but only 1 time. The second time I receive:
System.InvalidOperationException: 'Cannot set Visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after a Window has closed.'
Also, if the button is closed manually, it does not change the button content.
Finally, it does not place the window in the center of the screen. I try to place the window in the center of the screen using:
window.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
window.VerticalAlignment = VerticalAlignment.Center;
but this does not work, it place the window upper left corner.
Can anyone out there guide me on how this should be handled?
Window1 w1 = new Window1();
private void ShowByCoordinates(Window window, string screenName, int LeftTransform, int TopTransform)
{
if (button4.Content.ToString() == "Send")
{
Screen s0 = Screen.AllScreens.FirstOrDefault(s => s.DeviceName == screenName) ?? Screen.PrimaryScreen;
Rectangle bounds = s0.WorkingArea;
window.Left = bounds.X + LeftTransform;
window.Top = bounds.Y + TopTransform;
window.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
window.VerticalAlignment = VerticalAlignment.Center;
window.Show();
button4.Content = "Stop";
}
else
{
window.Close();
button4.Content = "Send";
}
}
private void Button4_Click(object sender, RoutedEventArgs e)
{
ShowByCoordinates(w1, "DISPLAY2", 1920, 0);
}
First, once you close the window, it's disposed and you can't show it again. Use Show() and Hide() instead.
When you set WindowStartupLocation to CenterScreen ther is a problem: after the window is shown any programmatical changes to its position will be ignored. So you can only do it once this way.
To do it manually, you need to set WindowStartupLocation to Manual and then set your window's Top and Left properties.
The next problem you'll have to consider is the fact that there may be multiple monitors. If you only need to center the window on the monitor set as primary in the system, then:
w.Left = (SystemParameters.WorkArea.Width - w.ActualWidth) / 2 + SystemParameters.WorkArea.Left;
w.Top = (SystemParameters.WorkArea.Height - w.ActualHeight) / 2 + SystemParameters.WorkArea.Top
is enough. If you want to center the window on the current monitor, then you'll need to do something like this:
(method from here):
public static void PostitionWindowOnScreen(Window window, double horizontalShift = 0, double verticalShift = 0)
{
Screen screen = Screen.FromHandle(new System.Windows.Interop.WindowInteropHelper(window).Handle);
window.Left = screen.Bounds.X + ((screen.Bounds.Width - window.ActualWidth) / 2) + horizontalShift;
window.Top = screen.Bounds.Y + ((screen.Bounds.Height - window.ActualHeight) / 2) + verticalShift;
}
To call it:
TestWindow w;
//....
w = new TestWindow();
w.WindowStartupLocation = WindowStartupLocation.Manual;
w.Closed += w_Closed;
//....
private void w_Closed(object sender, EventArgs e)
{
// to make sure there is no disposed window to access when user closes it manually
w = null;
// or:
// w = new TestWindow();
}
private void Button_ShowWindow_Click(object sender, RoutedEventArgs e)
{
if (w == null) return;
PostitionWindowOnScreen(w, 0, 0);
w.Show();
}
private void Button_HideWindow_Click(object sender, RoutedEventArgs e)
{
if (w == null) return;
w.Hide();
}
First, if you Close window, you cannot Show it again as already mentioned. You need to use Hide instead of Close.
To center your screen, just use this line:
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
I want to create a sort of side-window next to another window.
It should resize with the mainwindow and also move with it when I drag the mainwindow. How do I do this?
the first thing you do is to create your second window.
SecondWindow secondwindow;
Then you call the window directly next to your MainWindow.
secondwindow = new Secondwindow();
secondwindow.WindowStartupLocation = WindowStartupLocation.Manual;
secondwindow.Left = this.Left + this.Width;
secondwindow.Top = this.Top;
secondwindow.Height = this.Height;
secondwindow.Show();
If you want the second window to resize with your MainWindow (I guess just the height) type this in your
MainWindow - SizeChanged - event.
private void mainwindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (secondwindow != null)
{
secondwindow.Left = this.Left + this.Width;
secondwindow.Top = this.Top;
secondwindow.Height = this.Height;
}
}
Same without the height-change for the LocationChanged.
private void mainwindow_LocationChanged(object sender, EventArgs e)
{
if (secondwindow != null)
{
secondwindow.Left = this.Left + this.Width;
secondwindow.Top = this.Top;
}
}
I've got a smaller image in my form. When the user hovers over the image it brings up a larger view of the image (that follows the mouse, but stays a certain distance from the mouse). In order to do this I am generating a Form with no FormBorderStyles when the cursor hovers the image.
The problem I'm running into is that the first form doesn't seem to detect any longer that the mouse is hovering or leaving the PictureBox once the form activates. The Form also doesn't follow the cursor.
Here is the slimmed down version of what I've got:
C#
bool formOpen = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.MouseHover += pictureBox1_MouseHover;
pictureBox1.MouseLeave +=pictureBox1_MouseLeave;
}
void pictureBox1_MouseHover(object sender, EventArgs e)
{
if (formOpen == false)
{
Form form = new Form();
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
form.BackColor = Color.Orchid;
//Show the form
form.Show();
form.Name = "imageForm";
this.AddOwnedForm(form);
//Set event handler for when the mouse leaves the image area.
//form.MouseLeave += form_MouseLeave;
//Set the location of the form and size
form.BackColor = Color.Black;
form.Dock = DockStyle.Fill;
form.Size = new Size(30, 30);
form.BackgroundImageLayout = ImageLayout.Center;
this.TopMost = true;
formOpen = true;
form.Location = new Point(Cursor.Position.X, Cursor.Position.Y);
}
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
//MessageBox.Show("Worked");
}
}
The MouseLeave (and other events) was not recognized because the opening of the popup window and especially making it topmost=true took away the focus from the original form and its PictureBox.
It also didn't move because not code for moving was provided..
Here are a few changes that will make the form move:
You need a reference to it at the form1 level
you need to move it in the MouseMove event
Note that Hover is a once-only type of event. It fires only once until you leave the control.. (Note: Setsu has switched from Hover to Enter. This works fine, but lacks the short delay before showing the 2nd Form. If you want that back you can either switch back to Hover or you can fake the hover delay by a Timer, which is what I often do.)
// class level variable
Form form;
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.MouseEnter += pictureBox1_MouseEnter;
pictureBox1.MouseLeave +=pictureBox1_MouseLeave;
pictureBox1.MouseMove += pictureBox1_MouseMove; // here we move the form..
}
// .. with a little offset. The exact numbers depend on the cursor shape
void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if ((form != null) && form.Visible)
{
form.Location = new Point(Cursor.Position.X + 5, Cursor.Position.Y + 5);
}
}
void pictureBox1_MouseEnter(object sender, EventArgs e)
{
// we create it only once. Could also be done at startup!
if (form == null)
{
form = new Form();
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
//form.BackColor = Color.Orchid;
form.Name = "imageForm";
this.AddOwnedForm(form);
form.BackColor = Color.Black;
form.Dock = DockStyle.Fill;
form.Size = new Size(30, 30);
form.BackgroundImageLayout = ImageLayout.Center;
//this.TopMost = true; // wrong! this will steal the focus!!
form.ShowInTaskbar = false;
}
// later we only show and update it..
form.Show();
form.Location = new Point(Cursor.Position.X + 5, Cursor.Position.Y + 5);
// we want the Focus to be on the main form!
Focus();
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
if (form!= null) form.Hide();
}
MouseHover = Occurs when the mouse pointer rests on the control. (msdn)
Try MouseMove instead.
Not sure how to explain this, but:
there is a control MyPopup, made out of ToolStripDropDown;
there are many based on MyPopup controls (call them popups);
there are no problems to open popup from the Form;
but there is is a problem to open popup from popup.
Problem is what after child popup is closed, parent popup stays on screen even when its parent Form get focus. The only way to close that stuck parent popup is to get focus to it (with the mouse) and hit Esc.
To have popup able to show another popup I have to trick Closing event:
void Popup_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
// prevent from closing when stay
if (_stay && e.CloseReason != ToolStripDropDownCloseReason.CloseCalled )
{
e.Cancel = true;
return;
}
}
Before of after closing child popup, parent popup has:
value of _stay is False;
the value of Popup.AutoClose is True;
I tried to "bring" mouse focus back to the parent popup with the following:
TopLevel=true no luck;
Focus(); no luck;
Focused=true; no luck;
AutoClose=true; no luck;
Captured=true; no luck;
Also tried setting above value to False and then to True, still no luck.
And here is some more code, which could be useful or not:
public class MyPopup : UserControl
{
protected bool _stay = false;
private ToolStripDropDown _popup;
private ToolStripControlHost _host;
public MyPopup()
{
// create popup
_popup = new ToolStripDropDown();
_popup.Margin = _popup.Padding = Padding.Empty;
_popup.AutoSize = false;
_popup.Closing += Popup_Closing;
// add host
_host = new ToolStripControlHost(this);
_host.Margin = _host.Padding = Padding.Empty;
_host.AutoSize = false;
_popup.Items.Add(_host);
}
public void Show(Control parent, int x, int y)
{
_popup.Show(parent, x, y);
}
public new void Hide()
{
_popup.Close();
}
private void Popup_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
// prevent from closing when stay
if (_stay && e.CloseReason != ToolStripDropDownCloseReason.CloseCalled )
{
e.Cancel = true;
return;
}
}
protected void PopupChildClosedDefaultEvent(object sender, EventArgs e)
{
// hide popup if mouse is outside of client region when closing child popup
if (!ClientRectangle.Contains(PointToClient(MousePosition)))
Hide();
else
{
// >> here I am trying different things <<
_popup.AutoClose = false;
_popup.AutoClose = true;
}
}
}
public class PopupParent: MyPopup
{
private void TestChildren()
{
_stay = true;
PopupChild popup = new PopupChild();
popup.Show(button1, 0, 0);
popup.Closed += PopupChildClosedDefaultEvent;
_stay = false;
}
}
public class PopupChild: MyPopup
{
}
Question: Is there any way to fix "broken" popup after it has lost its ability to autoclose on mouse event (clicking somewhere outside of the client area)?
Ok, morning bring some freshness to brains and I managed to solve that issue with following:
_popup.Close();
_popup.Show(_parent, _x, _y);
So I have to reshow popup to have it functioning as before. It flickers, but works.
I have a window with WindowStyle="none" and WindowState=Maximized" and now I'd like in my contextmenu set the MenuItem to switch the application to the other desktop.
whats the simplest way to do that?
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Interop;
Screen screen = Screen.FromHandle(new WindowInteropHelper(this).Handle);
int i;
for (i = 0; i < Screen.AllScreens.Length; i++)
{
if (Screen.AllScreens[i] == screen) break;
}
i++; i = i % Screen.AllScreens.Length;
this.WindowState = WindowState.Normal;
int x = 0;
for (int j = 0; j < i; j++)
{
x += Screen.AllScreens[j].Bounds.Width;
}
this.Left = x + 1;
this.WindowState = WindowState.Maximized;
This will move a maximised window to the next monitor. I didn't test it though as I have only one monitor. Moving a window that is not maximised is harder because the size of the new monitor is not necessarily the same as the size of the old monitor. You could leave out setting the WindowState and center the window on the screen, or get the x position of the window on the current monitor and add it to the new x position. When using the latter you need to check if the new position is still inside the monitor.
Also note that this only works if your monitors are set up next to each other. This will not work when monitors are stacked.
I've solve the problem
when click the maximized window with the MouseLeftButtonDown then minimized this and now can i drag this to the other screen. The MouseLeftButtonUp Methode maximized the window
private void win_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
click = new Point(e.GetPosition(this).X, e.GetPosition(this).Y);
win.WindowState = WindowState.Normal;
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
this.Left += e.GetPosition(this).X - click.X;
this.Top += e.GetPosition(this).Y - click.Y;
}
private void win_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
win.WindowState = WindowState.Maximized;
}
thx # all : )