Move a window with custom borders using the mouse - c#

I'm working on a C# project using WPF. In my MainWindow I just got rid of the default windows border and made an own border instead with a png file. I just set this as the background of the MainWindow.
Now I made some kinda tricky way to make my window move:
private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
mouseDown = true;
lastX = (int)e.GetPosition(this).X;
lastY = (int)e.GetPosition(this).Y;
}
private void Window_MouseUp(object sender, MouseButtonEventArgs e) {
mouseDown = false;
}
private void Window_MouseMove(object sender, MouseEventArgs e) {
if (mouseDown) {
int xDiff = (int)e.GetPosition(this).X - lastX;
int yDiff = (int)e.GetPosition(this).Y - lastY;
this.Left += xDiff;
this.Top += yDiff;
}
}
private void Window_MouseLeave(object sender, MouseEventArgs e) {
mouseDown = false;
}
Now this doesn't really work properly. This way the user can move the window at all clear spaces, even on Labels and TextBlocks. Is there a way to give the background or a border these kind of events? Or is there a better way to integrate borders?
Thanks in advance!

As you said, behavior is erratic when done manually but there's a fix for it.
This is the method in the framework that is specially for doing that :
http://msdn.microsoft.com/en-us/library/system.windows.window.dragmove(v=vs.110).aspx

Related

Redrawing issues when moving a control

I am trying to move some controls around on a WinForm with the mouse. I am using the code below. To see my issue start a new project in VS add the code below. Set the form BackGroundImage to any image then add any control. Set the control events for MouseUp, MouseDown, and MouseMove. Start debugging and click and move the control. The image in the form starts getting erased. I have tried several different suspend drawing classes and methods I have found on the net but nothing I have found lets me move the controls around without serious flickering or not being able to see the move. Any help would be appreciated.
P.S. If you set the same events to the up, move, and down events of the form, it moves fine with out any flickering.
private bool _mouseDown;
private Point _startPoint;
private void Event_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_mouseDown = true;
_startPoint = new Point(e.X, e.Y);
}
}
private void Event_MouseUp(object sender, MouseEventArgs e)
{
_mouseDown = false;
}
private void Event_MouseMove(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
Control s = sender as Control;
s.Location = new Point(e.X + s.Left - _startPoint.X, e.Y + s.Top - _startPoint.Y);
}
}

How to detect a full mouse click (both down and up) on a control?

In WPF with MVVM (and no code-behind), say I have a Rectangle. If the user clicks on the rectangle, I want to perform an action. I effectively want the action to occur on mouse up. However, I only want the action triggered if they performed a full click (i.e. both mouse down and mouse up) on the rectangle. If they clicked down over some other control, held the mouse down, moved it over the rectangle, and released the mouse, I do not want to trigger the action.
There is the MouseDown event and the MouseUp event, but what I effectively want is a "MouseClick" event (like in WinForms). Is there any built-in mouse click event/trigger/something functionality? If not, what would be the best way to approach this? Custom trigger? Attached behavior?
Well, it isn't perfect, but I created a custom trigger to solve the problem. I'm still open to any better solutions if anyone has one.
public class MouseClickTrigger : TriggerBase<UIElement>
{
private bool _isMouseDown;
protected override void OnAttached()
{
this.AssociatedObject.MouseDown += this.AssociatedObject_MouseDown;
this.AssociatedObject.MouseUp += this.AssociatedObject_MouseUp;
this.AssociatedObject.MouseLeave += this.AssociatedObject_MouseLeave;
}
protected override void OnDetaching()
{
this.AssociatedObject.MouseDown -= this.AssociatedObject_MouseDown;
this.AssociatedObject.MouseUp -= this.AssociatedObject_MouseUp;
this.AssociatedObject.MouseLeave -= this.AssociatedObject_MouseLeave;
}
private void AssociatedObject_MouseDown(object sender, MouseButtonEventArgs e)
{
this._isMouseDown = true;
}
private void AssociatedObject_MouseUp(object sender, MouseButtonEventArgs e)
{
bool fullClick = this._isMouseDown;
this._isMouseDown = false;
if (fullClick)
{
this.InvokeActions(e);
}
}
private void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
{
this._isMouseDown = false;
}
}
Whaaaaat??? I dont your problem... Why cant you do something like this:
private bool isMouseDownInRect = false;
<Rectangle Width="100" Height="100" MouseUp="UIElement_OnMouseUp" MouseDown="UIElement_OnMouseDown" Fill="Black"></Rectangle>
private void UIElement_OnMouseUp(object sender, MouseButtonEventArgs e)
{
if (isMouseDownInRect)
{
// My code
}
isMouseDownInRect = false;
}
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
{
isMouseDownInRect = true;
}
I hope this is what you asking for.
EDIT:
Dont forget to handle the mouse_enter/leave event...

Make a TabPage flash on event

I'm in the stages of making a program which will require a tabpage to flash when an event happens
I've googled around, and i came across this: Blink tab header on receiving event. This is similar, but uses WPF, and i'm using WinForms, and i'm not even sure that does what i want :L
I've also found this: C#: Flash Window in Taskbar via Win32 FlashWindowEx. This is what i want, but obvious for the whole form, and in the taskbar, not 'in form'
Anyone got any ideas?
I'm not saying this is the best way or even a great way to accomplish this, but it does work. I've used code similar to this when I needed to something similar.
The tabControl1 has two tabs and I blink tab 1 (the second tab).
For my example that I threw together, I set tabControl1's DrawMode property to "OwnerDrawFixed" and then a couple of buttons which start/stop the timer. The interval was something like 750ms but you could choose whatever, of course. On a timer1_Tick event, I swap out the current color and tell the tabControl1 to refresh itself. That'll make the DrawItem event get raised and then I either draw the rectangle the current color if it is tab page 1 or the backcolor if not. Then I draw the tabpage's text.
It works. Could use some tweaking for sure. Give it a whirl!
public partial class Form1 : Form
{
Color currentColor = Color.Green;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (currentColor == Color.Yellow)
currentColor = Color.Green;
else
currentColor = Color.Yellow;
tabControl1.Refresh();
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Stop();
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
if (timer1.Enabled && e.Index == 1)
{
e.Graphics.FillRectangle(new SolidBrush(currentColor), e.Bounds);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), e.Bounds);
}
Rectangle paddedBounds = e.Bounds;
paddedBounds.Inflate(-2, -2);
e.Graphics.DrawString(tabControl1.TabPages[e.Index].Text, this.Font, SystemBrushes.HighlightText, paddedBounds);
}
}

WPF intercept clicks outside a modal window

Is it possible to check when the user has clicked outside a modal window? I'd like to somehow circumvent the modal logic because if the window isn't displayed as modal, it will not be shown on top of the active window, and, for now, this is the only way to display it correctly. I haven't found a proper way to do just that (since the "deactivate" event will no longer be triggered..)
Even if it's a modal window (displayed with ShowDialog() calls), one can add some even handlers to the window's class and make it check for the mouse clicks outside the window like this:
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (posX < 0 || posX > this.Width || posY < 0 || posY > this.Height)
this.Close();
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
Point p = e.GetPosition(this);
posX = p.X; // private double posX is a class member
posY = p.Y; // private double posY is a class member
}
private void Window_Activated(object sender, EventArgs e)
{
System.Windows.Input.Mouse.Capture(this, System.Windows.Input.CaptureMode.SubTree);
}
This did the job for me, in a difficult context: mingled MFC, WindowsForms mammoth of an app - no interop, no other complicated stuff. Hope it helps others facing this odd behavior.
Well one way is to hook up the event handler on your main app and respond to it when you have that window open:
EventManager.RegisterClassHandler(typeof(Window), Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMousepDown), true);
or
EventManager.RegisterClassHandler(typeof(yourAppClassName), Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(OnMousepDown), true);
//this is just a sample..
private void OnMousepDown(object sender, MouseButtonEventArgs e)
{
if (thatWindowThatYourTalkingAbout.IsOpen)
..do something
}

Mouse events not fired

I'm making a C# WinForms application. The MouseMove and MouseClick events of the form aren't getting fired for some reason. (I'm probably going to feel like an idiot when I find out why.)
It is a transparent form (TransparencyKey is set to the background colour) with a semi-transparent animated gif in a Picture Box. I am making a screensaver.
Any suggestions?
EDIT:
MainScreensaver.cs
Random randGen = new Random();
public MainScreensaver(Rectangle bounds)
{
InitializeComponent();
this.Bounds = Bounds;
}
private void timer1_Tick(object sender, EventArgs e)
{
Rectangle screen = Screen.PrimaryScreen.Bounds;
Point position = new Point(randGen.Next(0,screen.Width-this.Width)+screen.Left,randGen.Next(0,screen.Height-this.Height)+screen.Top);
this.Location = position;
}
private void MainScreensaver_Load(object sender, EventArgs e)
{
Cursor.Hide();
TopMost = true;
}
private Point mouseLocation;
private void MainScreensaver_MouseMove(object sender, MouseEventArgs e)
{
if (!mouseLocation.IsEmpty)
{
// Terminate if mouse is moved a significant distance
if (Math.Abs(mouseLocation.X - e.X) > 5 ||
Math.Abs(mouseLocation.Y - e.Y) > 5)
Application.Exit();
}
// Update current mouse location
mouseLocation = e.Location;
}
private void MainScreensaver_KeyPress(object sender, KeyPressEventArgs e)
{
Application.Exit();
}
private void MainScreensaver_Deactive(object sender, EventArgs e)
{
Application.Exit();
}
private void MainScreensaver_MouseClick(object sender, MouseEventArgs e)
{
Application.Exit();
}
Excerpt from MainScreensaver.Designer.cs InitialiseComponent()
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.MainScreensaver_MouseClick);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MainScreensaver_MouseMove);
This isn't an answer to you question, but I'm leaving this answer in case anyone else stumbles upon this question while trying to debug this same issue (which is how I got here)
In my case, I had a class that was derived from Form.
I was also using TransparencyKey.
Some things I noticed
The events will not fire on the transparent parts of the form.
The events will not fire if the mouse cursor is over another control on the form.
The events will not fire if you override WndProc and set the result of a WM_NCHITTEST message. Windows doesn't even send out the corresponding mouse messages that would cause the .NET events.
My Solution
In my constructor, I had forgotten to call InitializeComponent().
Which was where the event handlers were being bound to my controls.
Events were not firing because the handlers were not being bound.
Are you sure that your form has focus? If your form does not have focus, the mouse events will not be fired.

Categories