WPF Move two windows together - c#

I have two types of windows: Main and Child. When I move main, all child windows must move also. All my windows have style None, so I use DragMove. For moving child I use LocationChange of Main. And if I start moving main window fast, child move with some delay. My windows are stick one to another, so when moving main window fast, some gaps appears.
I use this question
Move two WPF windows at once?
How can I reduce this gaps?
some code:
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
StickyWindow.ParentWndStartMove(this);
this.DragMove();
}
here I move all children
public static void ParentWndMove(Window parentWindow)
{
for (int i = 0; i < windowsToMove.Length; i++)
{
if (windowsToMove[i])
{
windows[i].Top += -(parentWindowPosition.Y - parentWindow.Top);
windows[i].Left += -(parentWindowPosition.X - parentWindow.Left);
}
}
parentWindowPosition.X = parentWindow.Left;
parentWindowPosition.Y = parentWindow.Top;
}

I'm going to make an assumption based on your code fragment that parentWindowPosition
is a struct or class that has X and Y initialized to the Left and Top values of your MainWindow.
If that is the case then only thing you need to do in your MouseLeftButtonDown handler is call DragMove()
private void MainWindow_OnMouseLeftButtonDown(object sender,
MouseButtonEventArgs e)
{
DragMove();
}
Register a handler on the LocationChanged event of your MainWindow.
LocationChanged += MainWindow_OnLocationChanged;
which calls your ParentWndMove() method
private void MainWindow_OnLocationChanged(object sender, EventArgs e)
{
ParentWndMove(sender as Window)
}
This code works on my system with no delays no matter how quickly I drag the main window and the window positions never get out of sync.
NOTE: The ParentWndMove() method you posted has some compile time errors. I'm posting a fixed version for reference
public static void ParentWndMove(Window parentWindow)
{
for (int i = 0; i < windowsToMove.Length; i++)
{
if (windowsToMove[i] != null)
{
windowsToMove[i].Top += -(parentWindowPosition.Y - parentWindow.Top);
windowsToMove[i].Left += -(parentWindowPosition.X - parentWindow.Left);
}
}
parentWindowPosition.X = parentWindow.Left;
parentWindowPosition.Y = parentWindow.Top;
}

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 ParentWindow class public static ParentWindow instance; then instance = this;) :
public ChildWindow()
{
Owner = ParentWindow.instance;
InitializeComponent();
}
Then I add an event handler in the Parent Class to fire when the Parent is moving:
public ParentWindow()
{
InitializeComponent();
LocationChanged += new EventHandler(Window_LocationChanged);
}
Now I loop through all the windows owened by the ParentWindow 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);
}
}

Related

Do I have a memory Leak, in my FlowLayoutPanel?

I am using FlowLayoutPanels. One user control has a FlowLayoutPanel, and when a button is clicked on that panel a Custom User Control is created and added to that flowlayout. Inside that Custom User Control I have a button customButton2 and a handler customButton2_Click. And when customButton2 clicked I want to remove the current UserControl from that FlowLayout. As you can see I tried to disposed them inside customButton2_Click. However when I add or remove a custom user control, memory usage increases. As I said even if I delete something it increase the memory. I wrote a dispose and -= event handler for that button but nothing changes! Doesn't matter if I add or remove, memory usage increase no matter what. This is my main problem. Could you please help me with that?
My main user control that has the FlowLayoutPanel object. Moreover this control adds the custom user controls to FlowLayout
public partial class TodoList : UserControl
{
public TodoList()
{
InitializeComponent();
TodoListFlowLayout.HorizontalScroll.Enabled = false;
TodoListFlowLayout.HorizontalScroll.Visible = false;
TodoListFlowLayout.HorizontalScroll.Maximum = 0;
TodoListFlowLayout.AutoScroll = true;
}
public void button1_Click(object sender, EventArgs e)
{
if (this.TodoListFlowLayout.Controls.Count >= CommonVariables.TotalNumberOfTodoElement)
{
// Some Error message
return;
}
TodoListPanel todoPanel = new TodoListPanel(TodoListFlowLayout);
TodoListFlowLayout.Controls.Add(todoPanel);
TodoListFlowLayout.Invalidate();
}
}
My custom user control:
public partial class TodoListPanel : UserControl
{
System.Windows.Forms.FlowLayoutPanel flowLayoutPanel;
public TodoListPanel(System.Windows.Forms.FlowLayoutPanel flowLayout)
{
// This control has 1 label 2 custom buttons and a one panel.
InitializeComponent();
this.label1.Click += todo_Element_Panel_Click;
this.customPanel1.Click += todo_Element_Panel_Click;
flowLayoutPanel = flowLayout;
}
private void customButton2_Click(object sender, EventArgs e)
{
this.customPanel1.Click -= todo_Element_Panel_Click;
this.customButton2.Click -= customButton2_Click;
this.customButton1.Click -= customButton1_Click;
this.label1.Click -= todo_Element_Panel_Click;
foreach (TodoListPanel control in flowLayoutPanel.Controls)
{
if (this == control)
control.Dispose();
}
this.customPanel1.Dispose();
this.customButton2.Dispose();
this.customButton1.Dispose();
this.label1.Dispose();
this.Dispose();
this.flowLayoutPanel.Controls.Remove(this);
}
private void customButton1_Click(object sender, EventArgs e)
{
// Somethings happening
}
void todo_Element_Panel_Click(object sender, EventArgs e)
{
// Somethings are happening here too
}
}
How can I handle this memory leak? Or Do I really have a memory leak? Please see my Diagnostic tool:
After yellow pointer shows up which indicates the Garbadge Collecter is running, I removed bunch of custom user controls, even if I removed them the memory usage increased!!

How do you keyboard focus on a specific item?

I am making a game where I need a constant keyboard listener (to navigate through the game). I tried getting the keyboard focus to one place and let it stay there using a seperate thread in a while true loop. This seems to crash my program.
Question:
Is there a method to get my keyboard focused on one element so I can grab my key input from there?
What can I use?:
something that works without throwing exceptions
something I can use in combination with other text input
something that doesn't take hours to compile
something that is easy to build another program (im not super good at c#)
What have I tried?
public MainWindow()
{
InitializeComponent();
Thread keyboardfocus = new Thread(GetFocus);
keyboardfocus.Start();
}
private void GetFocus()
{
while (true)
{
Keyboard.Focus(KeyboardButton);
}
}
private void KeyboardButton_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Z)
{
map.PosUp -= 1;
MainCanvas.Background = Brushes.Aqua;
}
else if (e.Key == Key.S)
{
map.PosUp += 1;
MainCanvas.Background = Brushes.Black;
}
}
Thanks
Add event handler for Window.Loaded and set there a focus to the desired control:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus(KeyboardButton);
}
Add event handler for the UIElement.LostKeyboardFocus in your case KeyboardButton and just set the keybord focus again to the KeyboardButton:
private void KeyboardButton_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Keyboard.Focus(KeyboardButton);
}

Apply parent mouse events to child elements

I am making little Windows Forms Application.
I have PictureBox (parent) and Label (child) in it.
The Parent's Mouse Events are working perfectly, but Mouse events generated by child elements are not reflected on the Parent. The Cursor also changes back to its default (arrow).
Is it possible to pass events generated by child Controls, e.g., the MouseEnter event, to the Parent Control?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Card.MouseEnter += new EventHandler(Card_MouseEnter);
Card.MouseLeave += new EventHandler(Card_MouseLeave);
Card.MouseDown += new MouseEventHandler(this.Card_MouseDown);
Card.MouseUp += new MouseEventHandler(this.Card_MouseUp);
}
void Card_MouseLeave(object sender, EventArgs e)
{
this.Card.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.card_bg));
this.Rename("Running!");
}
void Card_MouseEnter(object sender, EventArgs e)
{
this.Card.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.card_hover_bg));
}
private void Card_MouseDown(object sender, EventArgs e)
{
this.Card.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.card_click_bg));
}
private void Card_MouseUp(object sender, EventArgs e)
{
this.Card.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.card_hover_bg));
this.Rename("Please Wait...");
}
private void CardName_MouseDown(object sender, MouseEventArgs e)
{
}
void Rename(string args)
{
this.CardName.Text = args;
}
private void CardName_Click(object sender, EventArgs e)
{
}
}
         
This is what I have This is what I want to achieve
The first animation represents what I have now, the second is what I need to achieve :)
When I'm making pictureBox1.Controls.Add(label1) label1 is
disappearing and I tried bring to front and change color but couldn't
do it. Please if you will have any idea show me in provided code by me
to be understandable for me. Thank you all again and again :)
You'd use code like this, maybe in the Load() event of the Form:
private void Form1_Load(object sender, EventArgs e)
{
Point pt = CardName.Parent.PointToScreen(CardName.Location);
Card.Controls.Add(CardName);
CardName.Location = Card.PointToClient(pt);
}
This keeps the label in the same position as it was, but makes the picturebox the parent.
Not sure where you're going wrong. Here's an example showing it in action. Both the PictureBox (Card) and Label (CardName) are inside a Panel (panel1). Clicking on button2 toggles the visibility of the Card. Clicking on button1 makes Card the Parent of CardName. You can see that at first, only the Card toggles visibility, but after clicking on button1 and setting the Parent, both toggle visibility together since CardName is a Child of Card (it also changes its BackColor to match that of its new Parent):
Code:
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
Point pt = CardName.Parent.PointToScreen(CardName.Location);
Card.Controls.Add(CardName);
CardName.Location = Card.PointToClient(pt);
}
private void button2_Click(object sender, EventArgs e)
{
Card.Visible = !Card.Visible;
}
}
When I move mouse over label, panel thinks mouse left it and rises
MouseLeave event
Here is how you can tell if the cursor has actually left the BOUNDS of the Panel, as opposed to simply enter a child control within the Panel:
private void panel1_MouseEnter(object sender, EventArgs e)
{
panel1.BackColor = Color.Red;
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
Point pt = panel1.PointToClient(Cursor.Position);
if (!panel1.ClientRectangle.Contains(pt))
{
// we only get in here when the cursor leaves the BOUNDS of panel1
panel1.BackColor = Control.DefaultBackColor;
}
}
First of all, you should build a UserControl as a container for all your objects: it'd make everything simpler (the one I'm using here is actually a UserControl, modified to comply with your current setup).
When a Control other than the PictureBox is interacted with, you can decide whether you want to trigger a similar action on the main Control or perform a different action based on what event has been generated.
▶ When the Mouse Pointer enters you assembled Control, you want to change the default Cursor: then, when one of the Labels raises the Enter event, call the method of the main Control that handles this. An event handler is a method, you can call it.
▶ When a Label is clicked, you don't want to trigger the related action of the main Control: in this case, there's nothing to do, just handle this event and perform the required action.
▶ The Label should be child of the main Control. You're using a PictureBox, which is not a ContainerControl. You can add child controls to it anyway. You need to do this in code, since - as mentioned - the PictureBox is not designed to host Controls, thus you cannot drop one inside it: the Control you drop will be parented with the Container that hosts the PictureBox (your Form, here).
When you set the parent in code, you need to remember that the Location of the child control is relative to the old Parent, so you have to re-define it's position.
E.g: PictureBox.Bounds = (100, 100, 100, 200) / Label.Bounds = (100, 250, 100, 50)
When the PictureBox becomes Parent of your Label, the Label.Location is still (100, 250): so, now, it will be hidden, since it's outside the visible bounds of its new Parent. You have to reposition it in relation to the new host: its new Location should be (0, 150), to keep the previous relative position.
PictureBox.Control.Add(Label);
//[...]
Label.Location = new Point(Label.Left - PictureBox.Left, Label.Top - PictureBox.Top);
=> Label.Location = (100 - 100, 250 - 100) => (0, 150)
Or, centered horizontally:
Label.Location = new Point((PictureBox.Width - Label.Width) / 2, Label.Top - PictureBox.Top);
=> Label.Location = ((100 - 100) / 2, 250 - 100) => (0, 150) // <- Since both have the same Width
Or, using positions relative to the Screen:
var p = Label.PointToScreen(Point.Empty); // Relative to the ClientRectangle (Top/Left = (0, 0))
PictureBox.Controls.Add(Label);
Label.Location = PictureBox.PointToClient(p);
In any case, call BringToFront() after, to ensure that the new child Control is brought on top and anchor the Control, so it will keep its position and its Width will be bound to the Parent Width:
Label.BringToFront();
Label.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right;
Now, assuming you want to change the Cursor to Cursors.Hand when the Mouse enters your combined Control and reset to default when it leaves it:
▶ You want the Cursor to change shape in any case.
▶ You want to generate different actions when the PictureBox is clicked and when one of the Labels is clicked.
▶ Both Labels can have distinct actions when clicked.
→ In the visual sample, the Label above the PictureBox is named lblTitle, the Label inside the PictureBox, at the bottom, is named lblFooter.
→ The PictureBox is named ImageView.
Setup the handlers:
NOTE: With a UserControl, the events handling, e.g., in relation to MouseEnter, changes in:
// The Parent's MouseEnter calls OnMouseEnter
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
this.Cursor = Cursors.Hand;
}
// Child Controls just call the same method
private void Labels_MouseEnter(object sender, EventArgs e) => OnMouseEnter(e);
public Form1()
{
InitializeComponent();
Point p = lblFooter.PointToScreen(Point.Empty);
ImageView.Controls.Add(lblFooter);
lblFooter.Location = ImageView.PointToClient(p);
ImageView_MouseEnter += ImageView_MouseEnter;
ImageView_MouseLeave += ImageView_MouseLeave;
// Not added in the code here, do whatever is needed with this handler
ImageView_Click += ImageView_Click;
lblFooter.MouseEnter += Labels_MouseEnter;
lblFooter.MouseLeave += Labels_MouseLeave;
lblFooter.MouseClick += lblFooter_MouseClick;
lblTitle.MouseEnter += Labels_MouseEnter;
lblTitle.MouseLeave += Labels_MouseLeave;
lblTitle.MouseDown += lblTitle_MouseDown;
lblTitle.MouseUp += lblTitle_MouseUp;
}
private void ImageView_MouseEnter(object sender, EventArgs e) => this.Cursor = Cursors.Hand;
private void ImageView_MouseLeave(object sender, EventArgs e) => this.Cursor = Cursors.Default;
private void Labels_MouseEnter(object sender, EventArgs e)
{
ImageView_MouseEnter(ImageView, e);
// [...]
// Do stuff related to the Labels Enter event
}
private void Labels_MouseLeave(object sender, EventArgs e) {
ImageView_MouseLeave(ImageView, e);
}
private void lblTitle_MouseDown(object sender, MouseEventArgs e) {
// Perform actions when the Mouse button is held down lblTitle
}
private void lblTitle_MouseUp(object sender, MouseEventArgs e) {
// Perform actions when the Mouse button is released
}
private void lblFooter_MouseClick(object sender, MouseEventArgs e) {
// Perform actions on a Mouse Click event on lblFooter
}

C# mouse event for class object

First - I'm a graphics designer - not a programmer :/
I'm trying create simple aplication (C# windows Form application) with option to add some objects (PictureBox) and allow user to drag those PicturesBoxes on form (change their positon after adding to form).
I can do it for one PictureBox, but can't add function to all dinamic created objects :/
I have something like that for standard Picturebox4
public bool moveDetect = false;
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
private void pictureBox4_MouseUp(object sender, MouseEventArgs e)
{
if (moveDetect)
{
Point pozycja = new Point();
this.Cursor = new Cursor(Cursor.Current.Handle);
pozycja = this.PointToClient(Cursor.Position);
pictureBox4.Location = pozycja;
}
}
Does anyone know any tutorial showing how to add function like above to my simple class "myPictureBox : Picturebox"
My class is:
class myPictureBox : PictureBox
{
public bool moveDetect = false;
// constructor
public myPictureBox(int w, int h, string name)
{
this.Width = w;
this.Height = h;
this.Image = Image.FromFile("../../Resources/" + name + ".png");
Debug.WriteLine("Created ...");
}
}
Constructor works good and show "Created..." in output. Cant add function to all objects :/
Thanks and Regards ;)
If I understand correctly, your code works fine with the event handlers MouseUp and MouseDown when you are working with PictureBoxes that you create at design time using the designer.
You can add these same event handlers to controls that are created dynamically when you instantiate them:
MyPictureBox dynamicPicBox = new MyPictureBox(800, 600, "JustATest");
dynamicPicBox.MouseDown += pictureBox_MouseDown;
this adds an event handler that maps to the method pictureBox_MouseDown
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
Since your custom class is derived from PictureBox, it should recognize this type of event handler.

Listen the show / hide events for soft keyboard (Windows 8.1 RT, XAML)

How can I know when the soft keyboard is shown/dismissed in my app or within a page?
Found this snipplet in THIS article. But is not valid for WP 8.1 RT. How can I translate it or get a similar behavior?
public class MyApplication
{
public MyApplication()
{
// Grab the input pane for the main application window and attach
// touch keyboard event handlers.
Windows.Foundation.Application.InputPane.GetForCurrentView().Showing
+= new EventHandler(_OnInputPaneShowing);
Windows.Foundation.Application.InputPane.GetForCurrentView().Hiding
+= new EventHandler(_OnInputPaneHiding);
}
private void _OnInputPaneShowing(object sender, IInputPaneVisibilityEventArgs eventArgs)
{
// If the size of this window is going to be too small, the app uses
// the Showing event to begin some element removal animations.
if (eventArgs.OccludedRect.Top < 400)
{
_StartElementRemovalAnimations();
// Don't use framework scroll- or visibility-related
// animations that might conflict with the app's logic.
eventArgs.EnsuredFocusedElementInView = true;
}
}
private void _OnInputPaneHiding(object sender, IInputPaneVisibilityEventArgs eventArgs)
{
if (_ResetToDefaultElements())
{
eventArgs.EnsuredFocusedElementInView = true;
}
}
private void _StartElementRemovalAnimations()
{
// This function starts the process of removing elements
// and starting the animation.
}
private void _ResetToDefaultElements()
{
// This function resets the window's elements to their default state.
}
}
The article you quote is intended for Windows Runtime apps, but it has a minor bug. The InputPane is in Windows.UI.ViewManagement not in Windows.Foundation.Application. Change that and the rest should work fine.
I've reported the doc bug so it can be fixed.
Found the answer, registering for those events is enough:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
InputPane.GetForCurrentView().Showing += onKeyboardShowing;
InputPane.GetForCurrentView().Hiding += onKeyboardHidding;
}
private void onKeyboardShowing(InputPane sender, InputPaneVisibilityEventArgs args)
{
KeyboardVisible = true;
}
private void onKeyboardHidding(InputPane sender, InputPaneVisibilityEventArgs args)
{
KeyboardVisible = false;
}

Categories