WM_NCLBUTTONUP message not sent at the end of dragging a form, how to do so? - c#

EDIT: tl;dr go to the first comment.
This question stems from another question of mine Get MouseDown event when mouse goes down on Form border?
In that question I needed to have a form fire an event when the user pushed the left mouse button down on the form border (preparing to drag), which works perfectly. The problem is when the user has finished this action, by letting go of the left mouse button, I would also like to have an event fired.
To do so I produced this code to be placed in a "base form" class that other forms would be derived from. I have removed the FireMouseButton...() methods for succinctness; they fire custom events.
const int WM_NCLBUTTONUP = 0xA2;
const int WM_NCLBUTTONDWN = 0xA1;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCLBUTTONUP)
FireMouseButtonUp();
if (m.Msg == WM_NCLBUTTONDWN)
FireMouseButtonDown();
base.WndProc(ref m);
}
The problem with this is that the WM_NCLBUTTONUP message is not sent as I expected it. After reviewing the description for WM_NCLBUTTONUP I can see why though,
[WM_NCLBUTTONUP is] posted when the user releases the left mouse button while the cursor
is within the nonclient area of a window. This message is posted to
the window that contains the cursor. If a window has captured the
mouse, this message is not posted.
Because the form has captured the mouse while it is being dragged, it will not receive the WM_NCLBUTTONUP message. (It will if the form is maximized though). This question explains it a little better The curious problem of the missing WM_NCLBUTTONUP message when a window isn't maximised.
The answer to that question is somewhat helpful but causes a lot of confusion for me. In the code below I have a small SSCCE, it implements some code given from the solution to the answer above, checking the WMNCHITTEST message to see if the mouse has been released;
The idea is that the WM_NCHITTEST should be sent when the mouse is moving within the form. So once a drag stops this message should be sent with the mouse position as DragStartPoint in the WndProc message arguments; where DragStartPoint is recorded when the WM_NCLBUTTONDOWN message is received.
The issue with this though is that the WM_NCHITTEST is not always sent after the start of a drag, only when the drag is started on the far sides of the top border (see pic below). The WM_NCLBUTTONDOWN message is always sent when clicking on the top border (never for sides or bottom). So that is fine, but the WM_NCHITTEST and as pointed out WM_NCLBUTTONUP are sent, but only sometimes.
How might I get the WM_NCHITTEST "test" to work in the code below so that I can be notified once the user has stopped dragging the form? (the "test" being checking the DragStartPoint in the if statement for WM_NCHITTEST)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MouseEventTest
{
public partial class Form1 : Form
{
Random rand = new Random();
public Form1()
{
InitializeComponent();
}
const int WM_NCHITTEST = 0x84;
const int WM_NCLBUTTONUP = 0xA2;
const int WM_NCLBUTTONDWN = 0xA1;
public Point DragStartPoint { get; set; }
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCLBUTTONUP)
{
label1.Text = "Mouse Up On Border";
}
if (m.Msg == WM_NCLBUTTONDWN)
{
label1.Text = "Mouse Down On Border";
Point pos = lParamToPoint(m.LParam);
DragStartPoint = this.PointToClient(pos);
Console.Out.WriteLine("DragStartPoint: " + DragStartPoint);
}
if(m.Msg == WM_NCHITTEST)
{
Point pos = lParamToPoint(m.LParam);
Console.Out.WriteLine("HtTestPnt: " + this.PointToClient(pos));
if (DragStartPoint == this.PointToClient(pos))
{
label1.Text = "Mouse Up HitTest";
}
}
base.WndProc(ref m);
}
private Point lParamToPoint(IntPtr lParamIn)
{
int x = lParamIn.ToInt32() & 0x0000FFFF;
int y = (int)((lParamIn.ToInt32() & 0xFFFF0000) >> 16);
return new Point(x, y);
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(42, 30);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(91, 13);
this.label1.TabIndex = 0;
this.label1.Text = "99999999999999";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(185, 75);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
}
}

Related

c# Exceptions Not Stopping at Location of exception Debugging Problem

my c# forms app (Vs 2022) in debug mode is just now beginning to show errors in weird places like String.Manipulation.cs. I know the error occurred in my app. But it shows it in some predefined code. I tried to clean and re-open the project, and recompile. But the debug behavior persists. The code below represents a section of the predefined code where it points.
The specific line is
"throw new ArgumentOutOfRangeException(paramName,message);"
the error details;
"System.ArgumentOutOfRangeException HResult=0x80131502
Message=startIndex cannot be larger than length of string. (Parameter
'startIndex') Source=System.Private.CoreLib StackTrace: at
System.String.ThrowSubstringArgumentOutOfRange(Int32 startIndex, Int32
length) in
//src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs:line
1878 at System.String.Substring(Int32 startIndex) in
//src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs:line
1837 at cabinetry.frmMain.ProcessScan() in
C:\Users\doug\source\cabinetry\cabinetry\frmMain.cs:line 487 at
cabinetry.frmMain.ScannerTime_Tick(Object sender, EventArgs e) in
C:\Users\doug\source\cabinetry\cabinetry\frmMain.cs:line 558 at
System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr
wparam, IntPtr lparam) at Interop.User32.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.Application.ComponentManager.Interop.Mso.IMsoComponentManager.FPushMessageLoop(UIntPtr
dwComponentID, msoloop uReason, Void* pvLoopData) at
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(msoloop
reason, ApplicationContext context) at
System.Windows.Forms.Application.ThreadContext.RunMessageLoop(msoloop
reason, ApplicationContext context) at cabinetry.Program.Main() in
C:\Users\doug\source\cabinetry\cabinetry\Program.cs:line 14
[DoesNotReturn]
private void ThrowSubstringArgumentOutOfRange(int startIndex, int length)
{
(string paramName, string message) =
startIndex < 0 ? (nameof(startIndex), SR.ArgumentOutOfRange_StartIndex) :
startIndex > Length ? (nameof(startIndex), SR.ArgumentOutOfRange_StartIndexLargerThanLength) :
length < 0 ? (nameof(length), SR.ArgumentOutOfRange_NegativeLength) :
(nameof(length), SR.ArgumentOutOfRange_IndexLength);
throw new ArgumentOutOfRangeException(paramName, message);
}
private string InternalSubString(int startIndex, int length)
{
Debug.Assert(startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
Debug.Assert(length >= 0 && startIndex <= this.Length - length, "length is out of range!");
string result = FastAllocateString(length);
Buffer.Memmove(
elementCount: (uint)result.Length, // derefing Length now allows JIT to prove 'result' not null below
destination: ref result._firstChar,
source: ref Unsafe.Add(ref _firstChar, (nint)(uint)startIndex /* force zero-extension */));
return result;
I can reproduce your situation:
Form1.cs
namespace WinFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AddControls();
}
}
}
Form1.Designer.cs
using System.Windows.Forms;
namespace WinFormsApp2
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void AddControls()
{
// Create text box
TextBox textBox = new TextBox();
textBox.Location = new Point(50, 50);
this.Controls.Add(textBox);
// create button
Button button = new Button();
button.Text = "add input";
button.Location = new Point(50, 80);
button.Click += (sender, e) =>
{
textBox.Text = "xxx"; // something
this.Controls.Add(button);
int argumentValue = -1;
int minimumValue = 0;
int maximumValue = 100;
if (argumentValue < minimumValue || argumentValue > maximumValue)
{
throw new ArgumentOutOfRangeException("argumentValue", argumentValue,
$"Parameter must between {minimumValue} and {maximumValue}.");
}
};
this.Controls.Add(button);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
}
#endregion
}
}
If I start debugging and click the button I created, click step into, I will jump in the external code(Not my code):
As Alexei metioned, you just need to select "Enable Just My Code" in Tools -> Options -> Debugging -> General:
By the way, "Enable Just My Code" is the default settings, so next time if you encounter some situations that something is normal before but become strange now, you can consider to reset the entire settings via these(In the way, you don't need to know which setting cause the issue, just reset entire settings.):
Reset environment settings:
turn off synchronized settings on a particular computer(This step is to prevent settings override):
]8

Prevent parent container from scrolling by the mouse wheel if a child (graphic) control is already scrolling

How to prevent the parent container from scrolling by the mouse wheel if the child (graphic) control is already focused and is scrolling?
I have a GMap.NET WinForms control embedded in a WinForms. Whenever that control is focused and scrolled via the mouse wheel, the parent form will also be scrolled. I just want the parent form to stay put while I'm scrolling the GMap.NET control via the mouse wheel. And when I want to scroll the parent form, I can always make GMap.NET control lose focus.
How to do what I want?
Here's my code:
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.gMapControl = new GMap.NET.WindowsForms.GMapControl();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.SuspendLayout();
//
// gMapControl
//
this.gMapControl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.gMapControl.Bearing = 0F;
this.gMapControl.CanDragMap = true;
this.gMapControl.EmptyTileColor = System.Drawing.Color.Navy;
this.gMapControl.GrayScaleMode = false;
this.gMapControl.HelperLineOption = GMap.NET.WindowsForms.HelperLineOptions.DontShow;
this.gMapControl.LevelsKeepInMemmory = 5;
this.gMapControl.Location = new System.Drawing.Point(525, 1);
this.gMapControl.MarkersEnabled = true;
this.gMapControl.MaxZoom = 2;
this.gMapControl.MinZoom = 2;
this.gMapControl.MouseWheelZoomEnabled = true;
this.gMapControl.MouseWheelZoomType = GMap.NET.MouseWheelZoomType.MousePositionAndCenter;
this.gMapControl.Name = "gMapControl";
this.gMapControl.NegativeMode = false;
this.gMapControl.PolygonsEnabled = true;
this.gMapControl.RetryLoadTile = 0;
this.gMapControl.RoutesEnabled = true;
this.gMapControl.ScaleMode = GMap.NET.WindowsForms.ScaleModes.Integer;
this.gMapControl.SelectedAreaFillColor = System.Drawing.Color.FromArgb(((int)(((byte)(33)))), ((int)(((byte)(65)))), ((int)(((byte)(105)))), ((int)(((byte)(225)))));
this.gMapControl.ShowTileGridLines = false;
this.gMapControl.Size = new System.Drawing.Size(198, 378);
this.gMapControl.TabIndex = 0;
this.gMapControl.Zoom = 0D;
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.BackColor = System.Drawing.Color.Black;
this.flowLayoutPanel1.Location = new System.Drawing.Point(1, 1);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(489, 885);
this.flowLayoutPanel1.TabIndex = 6;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScroll = true;
this.ClientSize = new System.Drawing.Size(745, 533);
this.Controls.Add(this.flowLayoutPanel1);
this.Controls.Add(this.gMapControl);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
private GMap.NET.WindowsForms.GMapControl gMapControl;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
gMapControl.MapProvider = GMapProviders.GoogleTerrainMap;
gMapControl.MinZoom = 5;
gMapControl.MaxZoom = 12;
gMapControl.Zoom = 7.5;
gMapControl.ShowCenter = true;
gMapControl.DragButton = MouseButtons.Middle;
}
}
This is not just a problem of the GMap.NET for sure, I've tested with other (proprietary) graphic control and it behaves all the same.
I'm not sure if there's a better way around this but here's a hacky workaround to stop the WM_MOUSEWHEEL message from reaching the control and still execute the zooming logic.
Add the following class to your project:
public class MyGMapControl : GMapControl, IMessageFilter
{
public MyGMapControl()
{
Application.AddMessageFilter(this);
}
protected override void Dispose(bool disposing)
{
if (disposing) Application.RemoveMessageFilter(this);
base.Dispose(disposing);
}
public bool PreFilterMessage(ref Message m)
{
const int WM_MOUSEWHEEL = 0x020A;
if (m.HWnd == this.Handle && m.Msg == WM_MOUSEWHEEL)
{
Point posOnScreen = new Point(m.LParam.ToInt32());
Point pos = PointToClient(posOnScreen);
int delta = m.WParam.ToInt32();
var args = new MouseEventArgs(MouseButtons.None, 0, pos.X, pos.Y, delta);
this.OnMouseWheel(args);
return true;
}
return false;
}
}
Then, use MyGMapControl instead of GMapControl.
Here, we're creating a MessageFilter to intercept the WM_MOUSEWHEEL message and return true in PreFilterMessage to stop the message from reaching the control. Now, the scrolling won't occur but neither will the zooming logic because it's implemented inside OnMouseWheel() which is triggered by the WM_MOUSEWHEEL message. So, we manually call the OnMouseWheel() method before returning true to ensure that the zooming occurs.
As Jimi suggested in the comments, you could override WndProc() of the control's parent container, check for WM_MOUSEWHEEL, and return if the mouse cursor is over the GMapControl:
protected override void WndProc(ref Message m)
{
const int WM_MOUSEWHEEL = 0x020A;
if (m.Msg == WM_MOUSEWHEEL)
{
if (gMapControl.Bounds.Contains(PointToClient(MousePosition))) return;
}
base.WndProc(ref m);
}

slow picture box

I am writing a simple Ludus Latrunculorum game for my project at school and am using Picture Boxes in order to represent the pieces for the game.
However, when I use a background image - any background image for panel I am placing the piece at, it draws them very slowly. As if it places 1 picture top left, then waits about 0.005 and places the next one, until the board is filled.
I've tried replacing the background image with a 1x1 white image, same outcome.
BUT, when I make the background a color (this.board.BackColor = Color.Green;) it prints the pieces immediately.
Furthermore, when I make the back color transparent, so I will see the original background of the whole form, once again, the print is very slow.
But when I use Color.Tan, which is my transparency key of the form, I see whatever is behind the form, and the pieces print immediately. Which I find very odd, as I am guessing it is more difficult for the CPU to fetch whatever is behind the form and print the pieces on it than it is to fetch the background image and print on that.
Why is that happening? How can I make the pictures print immediately?
Desired behaviour - Immediate print of the pieces.
Actual behaviour - Slow print of the pieces.
Short code to get same problem:
Form1.Designer.cs
using System.Drawing;
namespace WindowsFormsApplication6
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackgroundImage = (Image)Image.FromFile(#"C:\Users\gold\Documents\Visual Studio 2013\Projects\Ludus Latrunculorum\Ludus Latrunculorum\images\Background.png", true); // Comment that and see how it prints the pictures immediately
this.ClientSize = new System.Drawing.Size(907, 595);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
}
}
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PrintBoard();
}
private PictureBox[,] piecesImg;
private void PrintBoard()
{
this.piecesImg = new PictureBox[8, 8];
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
{
this.piecesImg[i, j] = new PictureBox();
this.piecesImg[i, j].ClientSize = new Size(52, 52);
this.piecesImg[i, j].Image = (Image)Image.FromFile(#"C:\Users\gold\Documents\Visual Studio 2013\Projects\Ludus Latrunculorum\Ludus Latrunculorum\images\White Pawn.png", true);
this.piecesImg[i, j].BackColor = Color.Transparent;
this.piecesImg[i, j].Location = new Point(j * 57, i * 57);
this.Controls.Add(this.piecesImg[i, j]);
}
}
}
}
My first advice is: don't use PictureBox, bacuse this control is heavy. If you want to draw an image, just draw it in OnPaint method.
Second advice: add all the images to Resources, so you will access them much easier just by name instead of full path.
And one more thing: remove the background. We will draw it as well. No need to set it. So, here's my full example.
Reources.resx
Form1.cs
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawImage(Properties.Resources.Background, 0, 0);
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
e.Graphics.DrawImage(Properties.Resources.Pawn, new Rectangle(j * 57, i * 57, 52, 52));
}
}
Application
Note that I set DoubleBuffered flag in constructor to eliminate flickering.
http://www.c-sharpcorner.com/Forums/Thread/45434/ solved the problem.
Should have enabled doublebuffering and changed the layout to stretch.

Control resizing mathematics

Ok... So I've got this pretty killer Screenshot system I've been using for a while... It pretty much involves creating a somewhat transparent Form that auto-sizes to fit all monitors... Which gives the screen(s) a "dark-out" effect... I then have a hidden "button" control whos position is set upon mouse-down... Then, until mouse-up, the button will resize in real-time to create a sort of "selection" area... The Button is granted full transparency to implement this effect.
Source Example: http://db.tt/LWxfDB6 [Also posted below]
I'm having two issues that are directly related, I believe.
1.) The coordinates are off for multimonitors, it properly returns the coordinates that are clicked upon (highlighted), but the highlight box (effect) is often on the wrong monitor.
2.) You can only select from top-left ---> bottom-right and not universal.
Sorry if I didn't explain it well, the source should explain better.
Thanks, in advance, for any and all help received. :)
:MarkRect.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;
namespace TW_Media_Chat_
{
public partial class MarkRect : Form
{
Point Point1;
Point Point2;
public MarkRect()
{
InitializeComponent();
// Programatically maximize to all monitors
Screen[] Screens = Screen.AllScreens;
int AllWidth = 0;
int AllHeight = 0;
for (int index = 0; index < Screens.Length; index++)
{
AllWidth += Screens[index].Bounds.Width;
AllHeight += Screens[index].Bounds.Height;
}
this.Width = AllWidth;
this.Height = AllHeight;
}
private void Transparency_MouseDown(object sender, MouseEventArgs e)
{
button1.Visible = true;
button1.Location = Cursor.Position;
Point1 = Cursor.Position;
}
private void Transparency_MouseUp(object sender, MouseEventArgs e)
{
this.Visible = false;
Point2 = Cursor.Position;
AjaxChatBridge.AjaxVars.Point1 = Point1;
AjaxChatBridge.AjaxVars.Point2 = Point2;
this.Close();
}
private void MarkRect_MouseMove(object sender, MouseEventArgs e)
{
this.button1.Width = Cursor.Position.X - this.button1.Left;
this.button1.Height = Cursor.Position.Y - this.button1.Top;
}
}
}
:MarkRect.Designer.cs:
namespace TW_Media_Chat_
{
partial class MarkRect
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.BackColor = System.Drawing.Color.Lime;
this.button1.ForeColor = System.Drawing.Color.Lime;
this.button1.Location = new System.Drawing.Point(220, 172);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(19, 18);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = false;
this.button1.Visible = false;
//
// MarkRect
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(490, 406);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "MarkRect";
this.Opacity = 0.5D;
this.Text = "Transparency";
this.TopMost = true;
this.TransparencyKey = System.Drawing.Color.Lime;
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Transparency_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MarkRect_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Transparency_MouseUp);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
}
}
You should implement control resizing logic easier:
void MarkRect_MouseMove(...)
{
var mouseX = Cursor.Position.X;
var originalMouseX = Point1.X;
button1.Left = Math.Min(mouseX, originalMouseX);
button1.Width = Math.Abs(mouseX - originalMouseX);
// the same for Y
}
You should post that code here. We are to lazy to go to your dropbox to see the code. There are easier questions to answer here.

Windows Forms Controls in a ScrollableControl and Events

I have noticed that the Click event, or other control behaviour, is not always fired when a control contained in a ScrollableControl (Panel, etc) is clicked on.
If the control being clicked doesn't have the focus and is only partially visible it is scrolled into view. This is what I am expecting, however the Click event doesn't get fired or other control behaviour doesn't occur.
If the control already has the focus and is only partially visible the events do get fired.
Checkbox - Scrolls into view, checked state does not change.
CheckedListBox - Scrolls into view, clicked item does not get selected.
TreeView - Scrolls into view, clicked node does not get selected.
Button - Scrolls into view, click event does not get raised.
To reproduce this you can do the following:
Add any of the above controls to a
Panel
Add an event handler for Click, SelectedItemChanged, etc
Resize the form so that scrollbars are visible on the panel
Scroll the panel so one of the controls is partially visible
Click the partially visible control
Is there any way to ensure the events get fired?
David,
It worked for me.
Code in Form1.Designer.cs:
namespace WindowsFormsApplication1
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.textBox2 = new System.Windows.Forms.TextBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.AutoScroll = true;
this.panel1.Controls.Add(this.textBox2);
this.panel1.Controls.Add(this.textBox1);
this.panel1.Location = new System.Drawing.Point(86, 75);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(176, 70);
this.panel1.TabIndex = 0;
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(109, 17);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(100, 20);
this.textBox2.TabIndex = 1;
this.textBox2.Click += new System.EventHandler(this.textBox2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(3, 17);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 0;
this.textBox1.Click += new System.EventHandler(this.textBox1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(493, 271);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "Form1";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.TextBox textBox1;
}
}
Code in Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void textBox1_Click(object sender, EventArgs e)
{
MessageBox.Show("Click1");
}
private void textBox2_Click(object sender, EventArgs e)
{
MessageBox.Show("Click2");
}
}
}

Categories