My main window has spawned a child window that's positioned on top to look like part of the main. I would like to move the child window in sync with the main but I'm not sure how.
My main window has my own title bar which event MouseLeftButtonDown calls this function:
public void DragWindow(object sender, MouseButtonEventArgs args)
{
DragMove();
UpdateChildWindowPosition();
}
This results in DragMove() executing on the main window moves the main window alone as I drag the title bar. UpdateChildWindowPosition() is not executed until I release the mouse at which it reads some element coordinates and sets the child window position - you see the child window snap to the location which is not desired.
How can I have the child window move in sync with the main window?
AH HAH!
My Main window has an event LocationChanged which I've tied to my UpdateChildWindowPosition(). LocationChange fires when (duh) the location changes so it's continuously firing as I move the window when DragMove() is being executed in my DragWindow posted above.
You can use the window's Left and Top properties to place the secondary window. Here's a rough bit of code as an example:
In the MainWindow code:
mDebugWindow.Left = this.Left + this.ActualWidth;
mDebugWindow.Top = this.Top;
In this case mDebugWindow is my child window. This code tells it to sit on the right hand side of the main window, with the tops of the windows aligned.
Hope this helps.
Here is what I did:
I first set an Instance of the Parent as the owner of the Child window, (make an instance by setting it in the MainWindow class public static MainWindow instance; then instance = this;) :
public ChildWindow()
{
Owner = MainWindow.instance;
InitializeComponent();
}
Then I add an event handler in the Parent Class to fire when the Parent is moving:
public MainWindow()
{
InitializeComponent();
LocationChanged += new EventHandler(Window_LocationChanged);
}
Now I loop through all the windows owened by the MainWindow to reset their margin:
private void Window_LocationChanged(object sender, EventArgs e)
{
foreach (Window win in this.OwnedWindows)
{
win.Top = this.Top + ((this.ActualHeight - win.ActualHeight) / 2);
win.Left = this.Left + ((this.ActualWidth - win.ActualWidth) / 2);
}
}
Can you expose a DragMove() method for the "child" form? Then just call it from the parent?
public void DragWindow(object sender, MouseButtonEventArgs args)
{
DragMove();
UpdatePosition();
childForm.DragMove();
childForm.UpdatePosition();
}
or if you are just using the mouse position to determine where to move the form, do the same calculations in your current DragMove() method and change the Form.Location property of your child form also?
Related
I am developing multiple instance WPF application. Application has a grid in a main screen and on double click of grid row, it opens child window. It has also functionality to open multiple child windows on double click of grid row from main screen.
Can anybody help me to prevent parent window to be close if child windows are active? So user can not able to close main window if child windows are active.
Set Owner property for those childs to Main Windows:
private void Button_Click(object sender, RoutedEventArgs e)
{
var wnd = new Window();
wnd.Owner = this;
wnd.Show();
}
Then in Main Window closing event handler:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (this.OwnedWindows.Count > 0)
{
MessageBox.Show("Child windows exists, you have to close'em first");
e.Cancel = true;
}
}
As a final point it could be helpful for you to know that you can get from anywhere in your code the app main windows with this:
System.Windows.Application.Current.MainWindow
So if you are using MVVM the above will help you in setting the Owner property.
You have two options:
1- You can use ShowDialog() to open the child window, but user can't interact with the parent window till the child is closed.
2- You can check all windows that are currently opened by checking
Application.Current.Windows
and then you can determine whether you want to close your window or not
Edit:
add the following event handler to your Parent.Closing event
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
foreach (var item in Application.Current.Windows)
{
Window window = item as Window;
if (window.Title == "YourChildWindowTitle")
{
// show some message for user to close childWindows
e.Cancel = true;
break;
}
}
}
In window closing command pass that if the child window is open disable closing functionality.
Or
you what you can do is make canexecute = false when a pop up is open and closing command is triggered.
Attach a function to the main window's 'Closing' event, and check to see if the child window is open. if it is, set
e.cancel = true;
I have a simple question really but I can't seem to find it. I am using WPF and I am creating a child window (Class Window) which displays a simple view. Now I can move the window around however what I would want is that it cannot move OUTSIDE the main window. (I think the Popup control has that behavior if I am not mistaking). Any easy way I can do that ?
Let me know if this isn't clear.
Thanks in advance.
Kind regards,
Qwin
Made you parent window as owner of child window and adjust the location
public MainWindow()
{
InitializeComponent();
LocationChanged += new EventHandler(Window_LocationChanged);
}
ChildWindow win = new ChildWindow();
win.Owner = this;
win.Show();
private void Window_LocationChanged(object sender, EventArgs e)
{
Console.WriteLine("LocationChanged - ({0},{1})", this.Top, this.Left);
foreach (Window win in this.OwnedWindows)
{
win.Top = this.Top + 100;
win.Left = this.Left + 100;
}
}
I have seen a couple posts on this, but they don't necessarily answer my question exactly.
I have a parent window that on its LocationChangedevent, it will grab a child window and move that along with it in a "snapped" fashion. I want to find an event and set a boolean value on the child form that would say "if the user has manually moved me, I will not re-attach to the parent."
Is there a way to detect if the user has moved the child window, rather than my parent window moving it?
I hope this makes sense.
Assuming you are using your child Window's Owner property to associate your parent Window to the child Window I would use an events-based approach.
In your child Window create an event that notifies listeners to disassociate (detach) the child Window from its parent:
public event EventHandler<EventArgs> DetachOwner;
You next need to determine when this event should be raised. For this we'll use three events in the child Window: Activated, Deactivated and LocationChanged.
LocationChanged will tell us when the child Window has moved but we'll need to filter out cases when the child Windows moves because it's following the parent Window. To do this we will need to know if the child Window is moving and it has focus. To track the focus state of the child Window create a bool field called HasFocus and set HasFocus to true in the Window's Activated event handler, and false in the Window's Deactivated handler.
Add this to your child Window:
private void Window_LocationChanged(object sender, EventArgs e) {
if (HasFocus) {
if (DetachChild != null) {
DetachChild(this, EventArgs.Empty);
}
}
}
bool HasFocus;
private void Window_Activated(object sender, EventArgs e) {
HasFocus = true;
}
private void Window_Deactivated(object sender, EventArgs e) {
HasFocus = false;
}
In the parent Window you'll subscribe to the child Window's DetachOwner event when you instantiate the child Window:
_child = new Child();
_child.Owner = this;
// Subscribe to the DetachOwner event.
_child.DetachChild += Child_DetachOwner;
This DetachOwner handler simply sets the child Window's Owner property to null:
void Child_DetachOwner(object sender, EventArgs e) {
((Child)sender).Owner = null;
}
You can expand on this approach to reattach the child Window to it's parent by creating a similar AttachOwner event in the child Window with a handler in the parent Window:
void Child_AttachOwner(object sender, EventArgs e) {
((Child)sender).Owner = this;
}
Basically I am having two problems with C#.NET MDI. You can download VS2010 solution which reproduces bugs here.
1) When programmatically hiding and showing again a maximized child form, it is not maximized properly again and becomes neither maximized or in normal state.
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
...
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
}
...
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
}
When child form is maximized, then programicaly hidden and shown again, it becomes something like this (please notice the menu bar - child form's control box appears, but child form is not maximized):
At this stage, child form cannot be moved around. However, I found a workaround for that, simply by showing and hiding a dummy child form, which forces the actual child form to become properly maximized. But this makes MDI area to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Maybe there are other workarounds to overcome this bug and not to make MDI area flicker with dummy child form?
private void workaround1Button_Click(object sender, EventArgs e)
{
dummyForm.Visible = true;
dummyForm.Visible = false;
}
2) When child form is maximized, the icon of the child form is displayed on menu bar. However, if you have to change the icon while the child form is maximized, the icon on the menu bar is not being refreshed (see the image above). I found a workaround for that too, which basically hides and shows menu bar. Icon gets refreshed, but it makes everything below menu bar to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Is there any other way to make menu bar to refresh the child form's icon?
private void workaround2Button_Click(object sender, EventArgs e)
{
menuStrip.Visible = false;
menuStrip.Visible = true;
}
Also I noticed that when parent form is in normal window state mode (not maximized) and you change the width or height of the form by 1 pixel, child form becomes maximized as it should be and child form's icon on menu bar gets refreshed properly and you don't need other workaround I described above. If I change the size of the form programicaly, form flickers by 1 pixel and I cannot do that, when parent form is maximized. Is there any way how I could invoke the repaint/refresh functionality which is called when you resize a form and which makes child form become maximized properly and the icon on the menu bar refreshed?
There's a bug in the implementation of the internal MdiControlStrip class, the control that displays the icon and the min/max/restore glyphs in the parent window. I haven't characterized it as yet, the code isn't that easy. A classic side effect of the bug is that the glyphs get doubled up, you found some other side-effects. The fix is simple though, delay creating the child windows until after the constructor is completed. Like this:
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e) {
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
dummyForm = new Form();
dummyForm.MdiParent = this;
dummyForm.WindowState = FormWindowState.Maximized;
base.OnLoad(e);
}
Have you tired using Hide/Show instead of setting visible to true/false?
Try:
private void showButton_Click(object sender, EventArgs e)
{
childForm.Show();
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Hide();
}
How about this workaround?
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
childForm.WindowState = (FormWindowState)childForm.Tag;
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
childForm.Tag = childForm.WindowState;
childForm.WindowState = FormWindowState.Normal;
}
UPDATE
I just gave you the idea how you could do. A better solution using the same idea as above would be a new base form which saves the windows state. See below. Derive your forms from FixedForm instead of Form:
public partial class FixedForm : Form
{
private FormWindowState lastWindowState;
public FixedForm()
{
InitializeComponent();
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (Visible)
{
WindowState = lastWindowState;
}
else
{
lastWindowState = WindowState;
WindowState = FormWindowState.Normal;
}
}
}
Found a way how to come around those bugs.
First of all you need to suspend painting for a form and its children. I found a very helpful thread here, which describes how to do it.
After suspending painting, you need call UpdateBounds method of the control and increase ClientRectangle Width or Height by one and then decrease it back to the same value it was before. This invokes layout functionality which makes everything to update/repaint. Last step is to enable painting. Not very nice solution I guess, but it works.
StopDrawing();
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height + 1);
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height - 1);
StartDrawing();
I find suspending painting very helpful not only for working around those two bugs, but also in general to make GUI work more smoothly. I guess this can help to remove any kind of flickering. However, this solution requires P/Invokes, which should be avoided in general.
Why not just manually reset required icon in menuStrip items, after the creation of the window:
menuStripMain.Items[0].Image = null;
I am using visual studio 2010 to do my C# GUI.
The current problem that I am facing is that after maximizing a window, it stays there but when I go to other forms, the window will go back to its original size.
How do I leave the maximized window all the way for all the forms, once I click the maximize button?
Heres an example:
User maximizes Form A
Form A maximized
User goes to Form B
Form B goes back to original size instead of a maximized window
What I want is when user maximizes a form, it stays that way till the program is closed or resized.
Assuming you're using WinForms, you can have either implement a shared FormWindowState manager or use a Multiple Document Interface (MDI) container.
Shared FormWindowState
You can register each of your forms with a class responsible for propagating changes in forms' FormWindowState.
public class FormWindowStateManager {
List<Form> _Forms;
...
public void Register(Form form) {
if(!_Forms.Contains(form)) {
_Forms.Add(form);
form.Resize += new EventHandler(Form_Resize);
}
}
public void Unregister(Form form) {
if(_Forms.Contains(form)) {
_Forms.Remove(form);
form.Resize -= new EventHandler(Form_Resize);
}
}
private void Form_Resize(object sender, EventArgs e) {
Form form = sender as Form;
if(form != null) {
if(form.FormWindowState == FormWindowState.Maximized || form.FormWindowState == FormWindowState.Normal) {
PropagateWindowState(form.FormWindowState);
}
}
}
private void PropagateWindowState(FormWindowState state) {
foreach(Form form in _Forms) {
if(form.FormWindowState != state) {
form.FormWindowState = state;
}
}
}
}
MDI Container
MdiParentForm.cs
IsMdiContainer = true;
MdiChildForm.cs
MdiParent = myParentForm; // instance of MdiParentForm
You can iterate through a form's MDI children using the form's MdiChildren property such that when on MDI child window changes its FormWindowState, the MDI parent form can apply the change to each of its children, similar to the shared FormWindowState approach.
These ideas are just off the top of my head but maybe they'll get you in the right direction.