Store two mouse click positions on canvas when checkbox enabled - c#

I have a checkbox at the moment where, when I click it, it should allow the user to click two places on a canvas, and then a messagebox with the coordinates of both clicks appear, and then the checkbox should uncheck itself. I've tried various things and keep running into a few problems.
Checking the box is a RoutedEventArgs where as clicking on the canvas is a MouseButtonEventArgs.
I'm unable to store the second mouse click (the first click appears twice); I've tried various for loops, while loops, etc.
I'm unable to get the box to uncheck itself after the message box appears, regardless of where I put the .Checked == false. I get an error that says system.windows.etcetc.checked can only appaer on the left hand side of += or -=.
I'd like to handle the whole thing in a function related to the checkbox aka the routedeventargs and not a canvas click method.
I can figure out #2 but 1 and 3 have me stumped.
This is a sample of the method which is subscribed to from a canvas mousedown in the xaml:
public void get_Scaling(object sender, MouseButtonEventArgs e)
{
Point startPoint;
Point endPoint;
while (Scale_btn.IsChecked == true)
{
startPoint = e.GetPosition(canvas1);
endPoint = e.GetPosition(canvas1);
System.Windows.MessageBox.Show("Start point is" + startPoint + "and end point is" + endPoint, "test", MessageBoxButton.OK, MessageBoxImage.Information);
}
}

There are a couple of issues I see.
1) The way to programmatically uncheck a CheckBox is to use the IsChecked property.
Scale_btn.IsChecked = false;
2) Remember that your while loop is running inside of a single MouseDown event handler. You won't be able to capture two different MouseDown events within that while loop. In order to achieve your goal, you need to bring the Point objects outside of the event handler and use another variable to keep track of which click you are capturing.
bool firstPointCaptured = false;
Point startPoint;
Point endPoint;
private void get_Scaling(object sender, MouseButtonEventArgs e)
{
if (Scale_btn.IsChecked == true)
{
if (!firstPointCaptured)
{
startPoint = Mouse.GetPosition(canvas1);
firstPointCaptured = true;
}
else
{
endPoint = Mouse.GetPosition(canvas1);
System.Windows.MessageBox.Show("Start point is" + startPoint + "and end point is" + endPoint, "test", MessageBoxButton.OK, MessageBoxImage.Information);
Scale_btn.IsChecked = false;
firstPointCaptured = false;
}
}
}

This is how you get mouse coords (you do not need e, so your question 1 is invalid).
Currently your starPoint == endPoint. Do you understand you have to get 2 mouse click events (while remembering points) before you are able show MessageBox?
You have to use IsChecked property, instead of Checked event to change checked state of CheckBox.

Related

Is the following possible when initiating an if pictureBox clicked event?

I have been trying to make a matching game and I recently learned that the following is possible:
if (checkBox1.checked = true)
{
MessageBox.Show("For Example.")'
}
Then why is the following not possible?
private void pictureBox1_Click(object sender, EventArgs e)
{
MessageBox.Show("Now Pick Another Hidden Picture!");
pictureBox1.Visible = false;
if (pictureBox13.Click = true)
{
MessageBox.Show("Great!");
pictureBox13.Visible = false;
double score = score + 1;
textBox1.Text = (score).ToString();
}
else
{
MessageBox.Show("Try Again!");
pictureBox13.Visible = true;
pictureBox1.Visible = true;
}
}
There is a error line under .Click , and the error is :
The event 'system.Windows.Forms.Control.Click' can only appear on the left hand side of += or -=.
What does this mean? And why does this work for checking checkboxes, but not for clicking pictureboxes? Thank in advance.
Checked is the state of a checkbox. At any given time, a checkbox is either checked or unchecked. Reading myCheckBox.Checked immediately returns the current state of the checkbox.
Click is an event. What do you expect if (pictureBox.Click == true) to do? Tell you if the pictureBox has been clicked within the last X seconds? Wait X seconds for the user to click (or not click) on the pictureBox?
In other words: If you check a checkbox, it stays checked until it is unchecked. Thus, it makes sense to check the current state of the checkbox. On the other hand, if you click a button, it is "clicked" for only an instant and then returns to being "unclicked". Thus, it just does not make sense to query the "clicked" state of a button.
PS: Comparisons are done with ==, not with =. The latter is an assigment. And, as Hugh correctly points out in the comments, if (boolean) is enough, if (boolean == true) is redundant.

Programatically select rows in a grid in MouseDown gets reset during MouseUp/MouseClick

I've got a MouseDown event on my GridView:
private void gdcSVNDefaultView_MouseDown(object sender, MouseEventArgs e)
{
var vw = (GridView)sender;
var hitInfo = vw.CalcHitInfo(e.Location);
DXMouseEventArgs.GetMouseArgs(e).Handled = SelectChildRows(hitInfo.RowHandle, vw);
}
private static bool SelectChildRows(int r, GridView view)
{
if (!view.IsGroupRow(r) || !view.GetRowExpanded(r))
return false;
var childRowCount = view.GetChildRowCount(r);
var first = view.GetChildRowHandle(r, 0);
var last = (first + childRowCount - 1);
view.SelectRange(first, last);
return true;
}
Screenshot of my form since not everyone is familiar with the DevExpress grids and might not know what i mean by a 'Group':
When you have a Group in the grid and click on that Group row instead of an actual 'data' row, I want to select all the child rows belonging to that Group.
The code works. If I click on a Group (for example, Type: Warning in my screenshot) and hold the mouse down I can see it select all the child rows... But as soon as I let up on the mouse, it de-selects them and selects just the group row. So if you just click quickly, like you normally would, you see them all flash quickly as as their selected state toggles.
Unfortunately, the Mouse events don't have any sort of "Handled" property I can set to make the MouseUp / Click not fire. I tried moving the code in my MouseDown to the MouseUp event and it doesn't even temporarily select everything. DX also has a "RowClick" event, tried it there... same results as the MouseUp.
Any ideas on how I can "cancel" those events?
Edit: Turns out there is a Handled property if you cast the MouseEventArgs to a DXMouseEventArgs object... But it still observes the same behavior.
Alright, so I found out that I need to set Handled in both the MouseDown and MouseUp events in order to get the behavior desired:
public class MyForm
{
private bool _b;
private void gdcSVNDefaultView_MouseDown(object sender, MouseEventArgs e)
{
var vw = (GridView)sender;
var hitInfo = vw.CalcHitInfo(e.Location);
if (hitInfo.HitTest == GridHitTest.RowGroupButton)
return;
_b = false;
if (vw.IsGroupRow(hitInfo.RowHandle))
_b = SelectChildRows(hitInfo.RowHandle, vw);
DXMouseEventArgs.GetMouseArgs(e).Handled = _b;
}
private void gdcSVNDefaultView_MouseUp(object sender, MouseEventArgs e)
{
DXMouseEventArgs.GetMouseArgs(e).Handled = _b;
}
private static bool SelectChildRows(int r, GridView view)
{
if (!view.GetRowExpanded((r)))
return false;
if (ModifierKeys != Keys.Shift && ModifierKeys != Keys.Control)
view.ClearSelection();
var childRowCount = view.GetChildRowCount(r);
var first = view.GetChildRowHandle(r, 0);
var last = (first + childRowCount - 1);
view.SelectRange(first, last);
return true;
}
}
Note: This IF block is NOT required for the core functionality. I found that if I click on multiple Groups it was adding that Range to the current Selection, which might be unexpected behavior for the end user. I added a check to see if the user is holding down the Control or Shift keys when they click the Group row. If not, then clear the current selection and select the new range
Have you tried using the Click event instead of MouseDown? Might be worth a shot. From here:
Note that the Click event also fires after the mouse button has been released. The difference is that the Click event is only raised if the mouse pointer is within the View when releasing the mouse button.

C# drag n drop, start drag operation in mouse_down ? conflicts with click

I have a C# WinForms application with a GridView on a Form wich shows records from the database containing blobs (files PDF/JPG/etc.) stored in a database.
I can doubleclick on a row in the grid, to write the blob to disk and open the file.
I can single-click on rows to select one or more rows (using ctrl+shift)
I can drag files onto the grid to add the files as rows to the grid (and database)
Now I want the user to be able to drag one or more rows from the grid to, for instance, the desktop or a mailclient but cannot figure out in what event to start the 'drag' operation.
When a user selects one or more file he/she does that using the left-mousebutton, dragging uses the same left-mousebutton, both events trigger the mouse-down event. How does one determine what the user is about to do?
I have tried starting the drag operation in the mouse-down event, but that doesn't work if I want to select multiple rows, every time I click on a row a drag operation starts...
how is that handled in the windows explorer for instance?
How does one detect what the user is trying to do?
I have got it working now. However I did not use a timer as suggested.
In Mouse-Down I set a flag and store X,Y point, then in mouse-up I reset the flag and in Mouse-move I calculate movement based on stored X,Y poiny, when movement is more that 10pixels in X or Y direction I start drag-operation.
Here's the code.
'
private bool DraggingFromGrid = false;
private System.Drawing.Point DraggingStartPoint = new System.Drawing.Point( );
void GridControlBrowser_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
DraggingFromGrid = true;
DraggingStartPoint = new System.Drawing.Point(e.X, e.Y);
}
}
void GridControlBrowser_MouseUp(object sender, MouseEventArgs e)
{
if (DraggingFromGrid)
{
DraggingFromGrid = false;
}
}
void GridControlBrowser_MouseMove(object sender, MouseEventArgs e)
{
if (DraggingFromGrid)
{
if (System.Math.Abs(e.X - DraggingStartPoint.X) > 10 ||
System.Math.Abs(e.Y - DraggingStartPoint.Y) > 10)
{
StartDragging();
}
}
}
private void StartDragging()
{
DraggingFromGrid = false;
// create files
var _criteria = this.GetSelectionFromGrid();
var _files = new List<string>();
... retrieve filenames and store in _files List ...
var _data = new DataObject(DataFormats.FileDrop, _files.ToArray());
DoDragDrop(_data, DragDropEffects.Copy);
}
'
I had a similar issue in that adding dragging to a form was interfering with existing double click functionality. I found a very simple solution:
void GridControlBrowser_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Clicks != 2)
{
StartDragging();
}
}
This cancels dragging if there is a double click so that double clicking continues to work.
there is more then one way to do that. I strongly suggest you try some of them until you decide what's best for you. for example, you can use the mouse_down event to start the drag and drop by using a timer. if the user is clicking the mouse more then 0.5 seconds, u start the drag. the mouse_up event kill the drag/dropping.
another way is making the drag and drop only with some key pressed while clicking the mouse.

Odd object interaction with buttons, focusable property doing something strange

private void Page_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Right)
{
if (shipPosition < right)
{
x = x + 10;
shipPosition = shipPosition + 10;
ship.Margin = new Thickness(shipPosition, y, 0, 0);
}
}
}
XAML - KeyDown="Page_KeyDown"
I have a rectangle named ship, and above is the function to move it, to be executed on right or left arrow key button press. For some reason, this doesn't work. The "KeyDown="Page_KeyDown"" is the xaml that links the button press with the event. There is another grid containing buttons that moves every time a timer ticks, and when I click on a button and highlight it, then press the arrow keys, the ship starts to move, with the highlighted button being changed as well. Does anyone have any idea what is going on?
Update: I removed the is focusable property on the buttons, and that then stopped ship movement all together. So I think it is something to do with the changing of focus on buttons.
Try this :
Keyboard.AddKeyDownHandler(this, Page_KeyDown);
Put it in the appropriate method of your control (constructor, initialized, ...)
public MainWindow()
{
InitializeComponent();
Keyboard.AddKeyDownHandler(this, Page_KeyDown);
}

Track Bar Only fire event on final value not ever time value changes

I am working on a pretty basic C# visual studio forms application but am having some issue getting the track bar to act as I want it to so hoping someone in the community might have a solution for this.
What I have is a pretty basic application with the main part being a track bar with a value of 0 to 100. The user sets the value of the track to represent "the amount of work to perform" at which point the program reaches out to some devices and tells them to do "x" amount of work (x being the value of the trackbar). So what I do is use the track bars scroll event to catch when the track bars value has changed and inside the handler call out to the devices and tells them how much work to do.
My issue is that my event handler is called for each value between where the track bar currently resides and where ever it ends. So if it is slid from 10 to 30, my event handler is called 20 times which means I am reaching out to my devices and telling them to run at values I don't even want them to run at. Is there someway only to event when scroll has stopped happening so you can check the final value?
Just check a variable, if the user clicked the track bar. If so, delay the output.
bool clicked = false;
trackBar1.Scroll += (s,
e) =>
{
if (clicked)
return;
Console.WriteLine(trackBar1.Value);
};
trackBar1.MouseDown += (s,
e) =>
{
clicked = true;
};
trackBar1.MouseUp += (s,
e) =>
{
if (!clicked)
return;
clicked = false;
Console.WriteLine(trackBar1.Value);
};
For the problem #roken mentioned, you can set LargeChange and SmallChange to 0.
Try the MouseCaptureChanged event - that is the best for this task
A user could also move the track bar multiple times in a short period of time, or click on the track multiple times to increment the thumb over instead of dragging the thumb. All being additional cases where the value that registers at the end of a "thumb move" is not really the final value your user desires.
Sounds like you need a button to confirm the change, which would then capture the current value of the trackbar and send it off to your devices.
Try this with the trackbar_valuechanged event handler:
trackbar_valuechanged(s,e) {
if(trackbar.value == 10){
//Do whatever you want
} else{
//Do nothing or something else
}
}
I found a fairly reliable way to do this is to use a timer hooked up in the trackbar.Scroll event:
private Timer _scrollingTimer = null;
private void trackbar_Scroll(object sender, EventArgs e)
{
if (_scrollingTimer == null)
{
// Will tick every 500ms (change as required)
_scrollingTimer = new Timer()
{
Enabled = false,
Interval = 500,
Tag = (sender as TrackBar).Value
};
_scrollingTimer.Tick += (s, ea) =>
{
// check to see if the value has changed since we last ticked
if (trackBar.Value == (int)_scrollingTimer.Tag)
{
// scrolling has stopped so we are good to go ahead and do stuff
_scrollingTimer.Stop();
// Do Stuff Here . . .
_scrollingTimer.Dispose();
_scrollingTimer = null;
}
else
{
// record the last value seen
_scrollingTimer.Tag = trackBar.Value;
}
};
_scrollingTimer.Start();
}
}
I had this problem just now as I'm implementing a built in video player and would like the user to be able to change the position of the video but I didn't want to overload the video playback API by sending it SetPosition calls for every tick the user passed on the way to his/her final destination.
This is my solution:
First, the arrow keys are a problem. You can try your best to handle the arrow keys via a timer or some other mechanism but I found it more pain than it is worth. So set the property SmallChange and LargeChange to 0 as #Matthias mentioned.
For mouse input, the user is going to have to click down, move it, and let go so handle the MouseDown, MouseUp, and the Scroll events of the trackbar like so:
private bool trackbarMouseDown = false;
private bool trackbarScrolling = false;
private void trackbarCurrentPosition_Scroll(object sender, EventArgs e)
{
trackbarScrolling = true;
}
private void trackbarCurrentPosition_MouseUp(object sender, MouseEventArgs e)
{
if (trackbarMouseDown == true && trackbarScrolling == true)
Playback.SetPosition(trackbarCurrentPosition.Value);
trackbarMouseDown = false;
trackbarScrolling = false;
}
private void trackbarCurrentPosition_MouseDown(object sender, MouseEventArgs e)
{
trackbarMouseDown = true;
}
I had a similar problem, only with a range TrackBar Control. Same idea applies to this also, only it's easier for this case.
I handled the MouseUp Event on the TrackBar to launch the procedures I needed, only after you would let go of the mouse button. This works if you drag the bar to your desired position or just click it.
private void rangeTrackBarControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
YourProcedureHere();
}
i solved the problem for my application with two events:
catch the Trackbar-ValueChange-Event
whithin the value-change event disable the valuechange event and enable the MouseUp-Event
public MainWindow()
{
//Event for new Trackbar-Value
trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
}
private void trackbar_ValueChanged(object sender, EventArgs e)
{
//enable Trackbar Mouse-ButtonUp-Event
trackbar.MouseUp += ch1_slider_MouseUp;
//disable Trackbar-ValueChange-Event
trackbar.ValueChanged -= ch1_slider_ValueChanged;
}
private void trackbar_MouseUp(object sender, EventArgs e)
{
//enable Trackbar-ValueChange-Event again
trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
//disable Mouse-ButtonUp-Event
trackbar.MouseUp -= trackbar_MouseUp;
//This is the final trackbar-value
textBox.AppendText(trackbar.Value);
}
ATTENTION: this works if the trackbar is moved by mose. It is also possible to move the trackbar by keyboard. Then futher code must be implemented to handle this event.

Categories