Detect if user has moved window in WPF - c#

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;
}

Related

Access controls located on the main form when the child form closes

I have created a main form which is always visible to users... its got some menu options. This form (Main) has got a number of hidden buttons which I am trying to unhide from another child form once the child form closes. My question is..."how do you transfer control from child to Main or reference the buttons on the Main form once the child have close. Thanks in advance for all help and suggestions. Here is what I have got so far:-
//This event is in the child's form..
private void Registerbutton_Click(object sender, EventArgs e) {
.
. // carry out some work and close
.
}
this.Close();
Showbuttons();//custom procedure
//custom procedure use to display all the hidden buttons on Main form
public void Showbutton(){
foreach (Control c in ((Main)MdiParent).Controls){
if (c is Button){
((Button)c).Show();
}
}
}
Subscribe to the child form's FormClosed event:
var childForm = new ChildForm();
childForm.FormClosed += ChildFormClosedHandler;
childForm.Show();
Then once the child form closes it will show all the buttons that are direct descendants of the form.
private void ChildFormClosedHandler(object sender, FormClosedEventArgs e)
{
foreach (Button button in this.Controls.OfType<Button>()){
button.Visible = true;
}
}
If you only want the buttons to be shown after some specific function then you may need to set some property on the child and do a check through the sender argument.

Prevent to close parent window if child windows are active

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;

Best way to handle passing of Control.Checked state between forms

It's been a while since I've worked with Windows Forms applications. I have a Checkbox on the Main form and, based upon a certain condition, if the Second form needs to be opened to request additional data from the user, how should I pass (or get) back a message to the Main form from the Second form so I can tell whether or not it's okay to Check or Uncheck the Checkbox?
From what I can remember, I could use something like Pass by ref. Or is there a better way to accomplish this?
Since you are showing the child form as a dialog, and the parent form doesn't need it until the form as closed, all you need to do is add a property with a public getter and private setter to the child form, set the value in the child form whenever it's appropriate, and then read the value from the main form after the call to ShowDialog.
One way to do this would be to use an event.
In your child form, declare an event to be raised upon specific user interaction, and simply "subscribe" to this event in your main form.
When you instantiate and call you child form, you'd do like this:
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.MyEvent += frm_MyEvent;
frm.ShowDialog();
frm.MyEvent -= frm_MyEvent;
}
private void frm_MyEvent(object sender, EventArgs e)
{
textBox1.Text = "whatever"; //just for demo purposes
}
In your child form, you declare the event and raise it:
public event EventHandler MyEvent;
private void button1_Click(object sender, EventArgs e)
{
if (MyEvent!= null)
MyEvent(this, EventArgs.Empty);
}
Hope this helps

Which control has been clicked?

I have a problem with MouseEvents on my WinForm C# application. I want to get ALL mouse clicks on my application.
How to determine which control has been clicked ?(I'm beginner C#)
Try this:
private void Control_Clicks(object sender, EventArgs e)
{
Control control = (Control)sender; // Sender gives you which control is clicked.
MessageBox.Show(control.Name.ToString());
}
This, this or this may help.
Hope it helps.
private void Form1_Load(object sender, EventArgs e)
{
SetupClickEvents(this);
}
/// <summary>
/// This will loop through each control within the container and add a click handler to it
/// </summary>
/// <param name="container">The container whose children to handle clicks for</param>
private void SetupClickEvents(Control container)
{
foreach(Control control in container.Controls)
{
control.Click += HandleClicks;
}
}
private void HandleClicks(object sender, EventArgs e)
{
Control control = (Control)sender;
MessageBox.Show(string.Format("{0} was clicked!", control.Name));
}
If you're doing Windows Forms, you have several options :
Hook mouse event, and after figure out if the clicked component actually makes part of your application
You can declare a base class MyComponent : Control. That component overrides MousClick event and raise a special event notifying about a fact. Every control in your app derive from that control, so every control will notify about click happened on it. It's enough to subcribe
to thier events and process them as requested.
Just a couple of ideas...
You'd have to wire them all up to the same event handler. This can be done in the properties window for the controls in question. You could also write your own function to traverse the control tree and tie the function to each of their event handlers.
You can recursively traverse the Form.Controls collection with a foreach loop.
void attachGlobalHandler(Control aToParse, EventHandler aGlobalHandler)
{
foreach(Control lControl in aToParse.Controls)
{
attachGlobalHandler(lControl, aGlobalHandler);
lControl.Click += aGlobalHandler;
}
}
And then you call that on your form, with the name of the function you want to call:
attachGlobalHandler( Form1, myClickHandler );
And that should tie it to EVERY clickable control on the form. The sender argument of the handler should then always refer to the control that fired the event. That being said, I'd probably just attach individual event handlers, unless you need to treat multiple controls as a group.
WARNING: The code above is untested.
For the second question asked "How to determine which control has been clicked?" each control has events which may be handled in code.
The easiest way to know when a control has been clicked is to attached to the clicked event of a control which is done from the properties for the control. You may have to click the lightning bolt icon to see the events. Double-clicking beside the even will create an empty handler.
For example if you had a simple form with a single button attaching click events to the form and to the button will tell you when there is a click anywhere. In most cases the button click would be the most useful to handle.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Click(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
}
It's really simple!
On your click event in your Win-Form, You add
// Here is a modified version of your code:
private void Form1_Click(object sender, EventArgs e)
{
var control = Form1.ActiveControl;
}

Move two WPF windows at once?

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?

Categories