I tried this XAML:
<Slider Width="250" Height="25" Minimum="0" Maximum="1" MouseLeftButtonDown="slider_MouseLeftButtonDown" MouseLeftButtonUp="slider_MouseLeftButtonUp" />
And this C#:
private void slider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
sliderMouseDown = true;
}
private void slider_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
sliderMouseDown = false;
}
The sliderMouseDown variable never changes because the MouseLeftButtonDown and MouseLeftButtonUp events are never raised. How can I get this code to work when a user has the left mouse button down on a slider to have a bool value set to true, and when the mouse is up, the bool is set to false?
Sliders swallow the MouseDown Events (similar to the button).
You can register for the PreviewMouseDown and PreviewMouseUp events which get fired before the slider has a chance to handle them.
Another way to do it (and possibly better depending on your scenario) is to register an event handler in procedural code like the following:
this.AddHandler
(
Slider.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(slider_MouseLeftButtonDown),
true
);
Please note the true argument. It basically says that you want to receive that event even if it has been marked as handled. Unfortunately, hooking up an event handler like this can only be done from procedural code and not from xaml.
In other words, with this method, you can register an event handler for the normal event (which bubbles) instead of the preview event which tunnels (and therefore occur at different times).
See the Digging Deeper sidebar on page 70 of WPF Unleashed for more info.
Try using LostMouseCapture and GotMouseCapture.
private void sliderr_LostMouseCapture(object sender, MouseEventArgs e)
private void slider_GotMouseCapture(object sender, MouseEventArgs e)
GotMouseCapture fires when the user begins dragging the slider, and LostMouseCapture when he releases it.
I'd like to mention that the Slider doesn't quite swallow the entire MouseDown event. By clicking on a tick mark, you can get notified for the event. The Slider won't handle MouseDown events unless they come from the slider's... slider.
Basically if you decide to use the
AddHandler(Slider.MouseLeftButtonDownEvent, ..., true)
version with the ticks turned on, be sure that the event was handled previously. If you don't you'll end up with an edge case where you thought the slider was clicked, but it was really a tick. Registering for the Preview event is even worse - you'll pick up the event anywhere, even on the white-space between ticks.
Related
I am working on a WPF application which is being used on a Touch Screen Tablet. I develop using VS2015 IDE and I use my Mouse to debug.
I must handle buttons' down and up events to execute certain tasks. I use PreviewMouse and PreviewTouch event handlers and I have a problem in every case I use:
Case 1: Using PreviewMouseDown,PreviewMouseUp,PreviewTouchDown and PreviewTouchUp. For each button, I need to duplicate my code to include separate Touch and Mouse Event handlers but the exact same functionality. I do this for me to be able to use the Application (Mouse) and for the the user to use it (Touch). Problem: Touch Event Handlers executes Mouse Event Handlers; Causing the application to duplicate the behavior. Ex: A button that increments x by one, will increment by one if you "Click" it but increment by two if you "Touch" it.
Case 2: Using Click, PreviewMouseUp and PreviewTouchUp. Problem: The PreviewTouchUp and PreviewMouseUp do not get called on Mouse Click.
Case 3: Create a method for each button and call it from both Touch and Mouse events like How to get Touchscreen to use Mouse Events. Problem: Duplicate behavior (method gets called twice)
Case 4: Remove all Touch events since PreviewMouseDown and PreviewMouseUp are being executed on any Touch. The behavior works but I need to Touch certain positions on the button in order for it to execute. (Transparency? I must touch exactly one position - like a mouse?)
Case 5: Using MouseUp and MouseDown instead of Preview. Didn't work on Touch at all, touching any position on the button.
I want something similar to this Prevent a WPF application to interpret touch events as mouse events but only on the tablet. I still need to use my mouse in my environment. How can I fix that?
Button sample XAML:
<Button x:Name="locationScrollUpButton" Margin="0,5,5,0" Background="Transparent" Padding="0" Grid.Row="1" Grid.Column="1" PreviewMouseUp="locationScrollUpButton_PreviewMouseUp" PreviewMouseDown="locationScrollUpButton_PreviewMouseDown" BorderThickness="0" PreviewTouchDown="locationScrollUpButton_PreviewTouchDown" PreviewTouchUp="locationScrollUpButton_PreviewTouchUp" >
<StackPanel>
<TextBlock x:Name="locationUpButtonText" Text="Up" FontSize="13" Margin="0,2,0,4" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Image x:Name="locationUpButtonImage" Source="/ProjectName;component/Resources/CaptureView/Location-Scroll-Up-White.png" Width="55" Height="60"/>
</StackPanel>
</Button>
Check the StylusDevice property of the MouseEventArgs. If it is null, then the mouse event is not a promoted touch event. If it's not null, then the StylusDevice will be the touch device that initiated the touch that got promoted.
So I ended up doing it using a cool hack. Based on Ahmad's answer on this other question HERE we know the fire order of the handlers:
On Touch Devices:
TouchDown > PreviewMouseDown > TouchUp > PreviewMouseUp
On Non Touch:
PreviewMouseDown > PreviewMouseUp
And based on #M.Kazem comments here. The fix now looks something like this:
private bool ButtonPreview = true;
private void Button_TouchDown(object sender, TouchEventArgs e)
{
// task 1
ButtonPreview = false;
}
private void Button_TouchUp(object sender, TouchEventArgs e)
{
// task 2
// ..
}
private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (ButtonXPreview)
{
// task 1
}
else
ButtonXPreview = true;
}
private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (ButtonXPreview)
{
// task 2
}
else
ButtonXPreview = true;
}
I have a WinForm which contains a multitude of controls interdependent on each other for their visibility and content.
I have a pair of radio buttons, controlling a combobox's (ComboBoxA) enable/disable flag and content. The selection on this combobox controls the visibility of a checkbox. The checking of this checkbox controls another combobox's (ComboBoxB) visibility and content. Business requirements are quite complicated around these controls. As a result, I require the ability to fire of the events programmatically and through user action, doing different things in each case.
In the checkbox's case, I check it programmatically while loading data (if needed), which fires the CheckedChanged event which in turn does additional action controlling ComboBoxB. The code for this is pretty vanilla, nothing special, but my question is more theoretical than practical. Please keep reading.
Due to this requirement, I need a way to distinguish between programmatic checking and user action. I tried using the Click event and CheckedChanged event, setting a flag in the click event, signifying user action. Unfortunately, the CheckedChanged event fires before the Click event, dead-ending this trick.
Now, I tried using the MouseDown event to capture user action. But funnily enough, once the event fires, checkbox remains unchecked and the CheckedChanged event doesnt fire.
Now, I have managed to use a flag in the code to determine programmatic checking and use that to distinguish between the two, but I was curious as to why the MouseDown event didnt allow the checkbox to be checked. Any ideas? I searched online but either I didnt do a thorough job of it, or google is not returning the right results for me. I apologize if anybody is actually able to find a google result for this problem.
It's something else in your code, not the MouseDown event that's preventing the CheckChanged to be fired.
Here is how I know this:
I've added a checkbox and a button to an empty form, and added event handlers to Click on the button, and on the checkbox CheckedChanged, KeyDown and MouseDown events. I've also added to the form a string variable called LastEventRaised, and in the CheckedChanged I've simply shown a MessageBox:
string LastEventRaised = string.Empty;
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
MessageBox.Show("Checked changed " + LastEventRaised);
LastEventRaised = string.Empty;
}
private void checkBox1_KeyDown(object sender, KeyEventArgs e)
{
LastEventRaised = "KeyDown";
}
private void checkBox1_MouseDown(object sender, MouseEventArgs e)
{
LastEventRaised = "MouseDown";
}
private void button1_Click(object sender, EventArgs e)
{
LastEventRaised = "programmatically";
checkBox1.Checked = !checkBox1.Checked;
}
Each time the message box popped up I've got the correct message.
In my WP8 app that controls Lego Mindstorms I have a Button with UIElement.Hold Event that triggers method runMotor() When I release the Button motor keeps on going but I would like it to stop. Method for stopping is stopMotor(), I've already tried to assign it to KeyUp Event but it doesn't work. Any solutions?
You can try to call stopMotor() in ManupulationCompleted event. Note that ManipulationCompleted event will get invoked after any gesture manipulation including Tap, Double Tap, Hold, and other gesture. Take that into account. If application scenario is still simple, checking if motor already running before calling stopMotor in ManipulationCompleted event handler maybe enough :
private void MyButton_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
if(isMotorRunning) stopMotor();
}
I am trying to use the MouseClick event from the properties of a listView to handle left and right mouse clicks.
Unfortunately the event never seems to fire. (Double clicked on the event to create a property, entered a bit of simple code and placed a breakpoint on the first line). The same is true of several other events listed in the properties (ItemSelectionChanged seems to work but the other events I have tried don't fire.
Here is the code added:
In form.designer.cs:
this.listView1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseClick);
In form.cs:
private void listView1_MouseClick(object sender, MouseEventArgs e)
{
Some code
}
That method never gets called when I click on the listview. The listview is inside a tab on top of the stack.
I guess I am probably forgetting something very basic but what?
ListView is a bit unusual, its MouseClick event doesn't fire unless you click an item in the view. Workaround is to use the MouseDown or MouseUp event instead. You typically are much more interested in the ItemSelectionChanged event btw. You probably need its HitTest() method to see exactly what was clicked if you use MouseDown/Up.
I have a textbox in a groupbox, both with double click events. When I double click in the textbox both events are triggered.
How do I stop clicks in the textbox from passing through to the groupbox? I've tried putting "e.Handled = true;" at the end of the textbox_DoubleClick event but this makes no difference.
Because WPF uses a "tunneling / bubbling" model of event propagation, most events begin bubbling UP from the bottom of the visual tree. If you want to catch an event on the way down, there are Preview versions of the events that tunnel downwards. For example:
PreviewMouseDoubleClick
Set e.Handled = true in there.
In your GroupBox's DoubleClick event you could check the value of e.OriginalSource and if that value is not the GroupBox, ignore the event
private void TabItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is GroupBox)
{
// Your code here
}
}
I believe ClickEvents are actually Direct Events, and not Tunneled/Bubbled events, so setting e.Handled in one won't cancel the other.
Per MSDN Site for MouseDoubleClick
Although this routed event seems to follow a bubbling route through an
element tree, it actually is a direct routed event that is raised
along the element tree by each UIElement.
you should handle e.Handled in the PreviewDoubleClick because tunneled events happens before bubbled up ones.
also why would you need to handle that event in both textbox and groupbox ? as it is getting fired in both because 2 separate events are getting fired.