Here is my XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="844.025" Width="678" MouseUp="somethingClicked">
<Grid MouseUp="somethingClicked">
<StackPanel MouseUp="somethingClicked" Margin="0,0,10,0">
<Button x:Name="btnClickMe" Content="Click Me!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="101,22,0,0" MouseUp="somethingClicked"/>
<CheckBox x:Name="chkhandle" Content="CheckBox" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="241,28,0,0" RenderTransformOrigin="-0.588,1.188"/>
<ListBox x:Name="lstEvents" HorizontalAlignment="Left" Height="604" VerticalAlignment="Top" Width="416" Margin="29,66,0,0"/>
</StackPanel>
</Grid>
And here is the C# Code:
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
protected int eventCounter = 0;
public MainWindow()
{
InitializeComponent();
}
private void somethingClicked(object sender, RoutedEventArgs e)
{
eventCounter++;
String message = "#" + eventCounter.ToString() + ":\r\n" +
" Sender: " + sender.ToString() + ":\r\n" +
" Source: " + e.Source + ":\r\n" +
" Original Source: " + e.OriginalSource;
lstEvents.Items.Add(message);
e.Handled = (bool) chkhandle.IsChecked;
if (e.Handled)
lstEvents.Items.Add("Completed");
}
}
}
I have the following issues with this example:
1)The MouseUp event is not fired on clicking the button.
2)The event doesn't bubble up. Clicking somewhere on the form displays:
Sender:WpfApplication4.MainWindow:
Source:WpfApplication4.MainWindow:
Original Source: System.Windows.Controls.Border.
If I understand rightly, when button is clicked, first it should be executed at Window level (which it does now), then Grid, then stack and finally text label. Is the code wrong or is my understanding of the concept faulty?
The MouseUp event is not fired on clicking the button.
Because the first fires is an event at the Button.Click, and when it works, it conflicts with the event MouseUp. Quote from here:
ButtonBase inherits from UIElement, a Button will also have access to all of the mouse button events defined for UIElement. Because the Button does something in response to button presses, it swallows the bubbling events (e.g. MouseLeftButtonDown and MouseDown). You can still detect these lower level button press events by adding handlers for the tunneling events (e.g. PreviewMouseLeftButtonDown and PreviewMouseDown).
Try to replace the Button on Label, and you'll get the desired result:
Try handling the PreviewMouseDown event instead. You can still
attach that from XAML. In your handler
Attach the event handler in code instead. Use the signature of
AddHandler
.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Grid1.MouseUp += new MouseButtonEventHandler(Grid1_MouseUp);
}
private void Grid1_MouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Mouseup");
}
Microsoft wrote a very nice explanation Routed Events Overview
exactly the same thing will happen with MouseUpand PreviewMouseUp events
in your case the e.Handled = (bool) chkhandle.IsChecked; stops the routing of the event.
if you want to debug the events you can use Snoop it will illustrate very nicely which events happened on which objects and who handled them.
There is an override available to handle events, even though they were marked as handled. It requires that you add your handler through code as the following:
MainWindow.AddHander(UIElement.MouseUpEvent, new MouseButtonEventHandler(button1_MouseUp), true);
That last parameter specifies whether you want to accept events that were handled already or not. If you add that handler to your main window, you'll notice that the routed MouseUp events from your button are indeed bubbling up, (but their e.Handled indicates that they were already handled).
Related
In my WPF application, I want to handle user F5 strokes as refresh. In order to archieve that, I decided to utilize the NavigationCommands.Refresh command.
Inside the UI, I utilize the DataGridControl from Extended WPF Toolkit. The Problem: whenever the focus is within the data grid, the refresh command handler is not triggered.
This can be demonstrated with a very small sample:
<Window x:Class="WpfTests.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xd="http://schemas.xceed.com/wpf/xaml/datagrid">
<Window.CommandBindings>
<CommandBinding Command="NavigationCommands.Refresh" Executed="CommandBinding_Executed" CanExecute="CommandBinding_CanExecute"/>
</Window.CommandBindings>
<StackPanel>
<TextBox Text="Click me to get the focus out of DataGridControl"/>
<xd:DataGridControl/>
</StackPanel>
</Window>
Nothing fancy going on in code behind, I just use it to place breakpoints in the handler:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
}
Reproduce:
Start Application, press F5 - handler is executed
Click into the DataGridControl area, press F5 - handler is not executed
Click into the textbox, press F5 - handler is executed
So the question is, how can I ensure that my refresh handler is executed when the user presses F5 while focus is within the DataGridControl?
Ok, I finally stumbled upon the solution.
https://xceed.com/forums/topic/what-is-the-function-key-F5-in-datagrid-for/
Setting the DataGridControl.IsRefreshCommandEnabled property to False stops the datagridcontrol from consuming the F5 key for its own internal logic. Then the handler is called as expected.
I am having a simple WPF Ribbon Window using RibbonControlsLibrary.
In this Window I am having a RibbonComboBox which contains an Button Element. My intent is to close RibbonComboBox' dropdown once the Button is clicked. I do not want manipulate the IsOpen property of the RibbonComboBox, since the Button should be reused for different purposes. My idea was to handle the MouseDown event of the button and then set e.Handled to false
The XAML looks like this
<ribbon:RibbonWindow x:Class="WpfRibbonApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
xmlns:my="clr-namespace:WpfRibbonApplication3"
Title="MainWindow"
x:Name="RibbonWindow"
Width="640" Height="480">
<ribbon:Ribbon>
<ribbon:RibbonTab Header="Home">
<ribbon:RibbonGroup Header="Group1">
<ribbon:RibbonComboBox>
<ribbon:RibbonGallery>
<ribbon:RibbonGalleryCategory>
<ribbon:RibbonGalleryItem>
<my:CustomButton Content="Test" />
</ribbon:RibbonGalleryItem>
</ribbon:RibbonGalleryCategory>
</ribbon:RibbonGallery>
</ribbon:RibbonComboBox>
</ribbon:RibbonGroup>
</ribbon:RibbonTab>
</ribbon:Ribbon>
</ribbon:RibbonWindow>
The code behind looks as follows:
public CustomButton()
{
// Insert code required on object creation below this point.
AddHandler(MouseDownEvent,(RoutedEventHandler)Button_MouseDown,true);
}
private void Button_MouseDown(object sender, RoutedEventArgs e)
{
Console.WriteLine(string.Format("MouseDownEvent, e.Handled = {0}", e.Handled));
e.Handled = false;
}
The event gets fired but the Ribbon dropdown closes only when pressing the button the second time. Interestingly, the second time I press the button the MouseDown event handler does not get invoked. Can someone give me some hints on how to achieve closing of the ribbon on the first click in a clean manner?
You can give your RibbonComboBox a name, let's say x:Name="comboBox", then in the code behind in the mouse down event handler, you can simply do: comboBox.IsDropDownOpen = false;
I'm having issues with dynamically handling the MouseUp event. Test code with issue:
WPF:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="Button1" Content="Button1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button x:Name="Button2" Content="Button2" HorizontalAlignment="Left" Margin="10,37,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
C# behind:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Button2.MouseLeftButtonUp += something;
}
private void something(object sender, MouseEventArgs e)
{
MessageBox.Show("TEST");
Button2.MouseLeftButtonUp -= something;
}
}
}
Now, I want the MessageBox with the text "TEST" to show only the first time after I click Button2, after I've clicked Button1. It doesn't show up. The same code works with the Click event instead, but I need MouseUp to get the mouse position. I've confirmed that the first function fires, but the second doesn't no matter what I try. Help?
See the Remarks section in ButtonBase.Click:
The ButtonBase marks the MouseLeftButtonDown event as handled in the
OnMouseLeftButtonDown method and raises the Click event. Hence, the
OnMouseLeftButtonDown event will never occur for a control that
inherits from ButtonBase. Instead, attach an event handler to the
PreviewMouseLeftButtonDown event, or call AddHandler(RoutedEvent,
Delegate, Boolean) with handledEventsToo set to true.
Since MouseLeftButtonDown is handled internally, you will also get no
MouseLeftButtonUp event. You could however use the PreviewMouseLeftButtonUp event instead.
Got a problem with short cuts, any help/tips would be much appreciated!
Goal: I need to be able to handle short cut keys, with and without modifiers in my app.
So for instance i need to handle a key 'a' as well as 'CTR+a'. But I want to handle them only if no control handles these keys. For instance TextBox class takes most keys, including some commands like 'Ctrl+C' etc, so I don't want to intercept these events when TextBox will handle them.
I tried using Commands as well as attaching events to KeyUp to the Window, but, commands intercept keys before the TextBox gets a chance to view them, KeyDown bubbles to the Window level even if TextBox used the key! How can I get my window to get the keys that are NOT handled by any child control? Please see the code below that did not work for me. Also, since i have many different controls, I rather have a "proper" solution: I rather not attach handlers to each instance of a control in my window.
<Window x:Class="KeyTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="Help"
CanExecute="HelpCanExecute"
Executed="HelpExecuted" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="Help" Key="H" />
</Window.InputBindings>
<Grid>
<WrapPanel>
<TextBox Name="myLOG" Width="300" Height="200" Background="LightBlue" />
<TextBox Name="myINPUT" Width="300" Height="200" />
<Button Content="JUST FOR FUN" />
</WrapPanel>
</Grid>
And for C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace KeyTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private void HelpCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
myLOG.Text += "HELP CAN EXECUTE\n";
e.CanExecute = true;
e.Handled = true;
}
private void HelpExecuted(object sender, ExecutedRoutedEventArgs e)
{
myLOG.Text += "HELP EXECUTED!!!\n";
e.Handled = true;
}
public void myKeyUpHandler(Object sender, KeyEventArgs args)
{
myLOG.Text += "KEY UP EVENT! " + args.Key + "\n";
}
public MainWindow()
{
InitializeComponent();
this.KeyUp += new KeyEventHandler(myKeyUpHandler);
}
}
}
When the focus is in text box, pressing "h" triggers the command, even though i want 'h' to only go to the text box. Also, when inside textbox, pressing any alpha numeric key fires the KeyUp event, even though as far as I understand, textbox should have handled=true that event!
Thanks for help!
You need to investigate using the preview event types. They happen before other controls will handle the events. Then you want to stop the events bubbling. I belive you are doing that correctly with e.Handled.
Investigate this: http://msdn.microsoft.com/en-us/library/system.windows.input.keyboard.previewkeydown.aspx
Not sure how to do it in xaml for what you want to do. The expressions blend libraries can be quite helpful for spawning commands off of events. See here: http://jacokarsten.wordpress.com/2009/03/27/applying-command-binding-to-any-control-and-any-event/
Dude I think you need to use previewKeyDown or PreviewKeyUp Event instead of a keyup event here because PreviewKeydown and PreviewKeyup Event produce tunneling effect(OPPOSITE of bubbling effect where events where fired starting from the RootParent of the control which fired the event down the to control which originally fired the event(also know as original source)). you can take advantage of this tunneling effect for handling events rather that using events which are fired via bubbling effect. Another thing is that PreviewKeyDown and PrevieKeyup events where fired before keydown events occur. This could let you intercept the event in the cleanest way.
Another thing, I think you need to check the original source of the event so that you could select the controls that could fire this events.
Here is a sample code
public void nameOfCotrol_PreviewKeyDown(object sender, RoutedEventArgs e)
{
if((e.OriginalSource as Control).Name == "NameOfControls That would be allowed to fire the event")
{
You're stuff to be done here
}
else
{
e.handled = true;
}
}
I hope this could help in a small way. Thanks
Platform: Silverlight 4 / .NET 4
Description:
I have a ComboBox, a Textbox and a NumericUpDown.
<StackPanel Margin="10">
<ComboBox SelectionChanged="cmbChanged" Margin="3">
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
</ComboBox>
<TextBox x:Name="txt" TextChanged="txtChanged" Margin="3"/>
<CheckBox x:Name="chk" Checked="chkChecked" Unchecked="chkChecked" Content="Check box" Margin="3"/>
<ListBox x:Name="lst" Height="100" Margin="3"/>
</StackPanel>
A list is for debugging purposes.
Repro:
Note that there are event handlers for TextBox.TextChanged, CheckBox.Checked, CheckBox.Unchecked and ComboBox.SelectionChanged.
Here are the handlers:
private void cmbChanged(object sender, SelectionChangedEventArgs e)
{
lst.Items.Clear();
txt.Text = (sender as ComboBox).SelectedIndex.ToString();
chk.IsChecked = !chk.IsChecked;
}
private void txtChanged(object sender, TextChangedEventArgs e)
{
lst.Items.Add("Text Changed");
}
private void chkChecked(object sender, RoutedEventArgs e)
{
bool? chk = (sender as CheckBox).IsChecked;
lst.Items.Add("CheckBox Changed to " + chk);
}
Problem:
In the combobox's event handler, I set the text in the textbox BEFORE setting the check state of the checkbox. However, if you take a look at the picture below, you will see that the event handler for the CheckBox.Checked gets called before TextBox.TextChanged.
The problem is obviously in the asynchronous execution of the TextBox.TextChanged event, as stated in the MSDN definition:
The TextChanged event is asynchronous. The event cannot be canceled.
I really need these event handlers to execute exactly in the order they are changed.
Question:
Is there any simple way to achieve what I need?
Perhaps it might be better to call your piece of business logic directly, instead of relying on the event handlers. You can always remove and add the EventHandler in case you don't want to hit that trigger in your particular situation:
//Remove event handlers:
CheckBox.Checked -= chkChecked;
TextBox.TextChanged -= txtChanged;
//Call your business stuff here
//You can also 'safely' set values on your textbox and
//checkbox since they wont trigger events now.
//Re-add event handlers, so they react on user input again:
CheckBox.Checked += chkChecked;
TextBox.TextChanged += txtChanged;
I'm not a Silverlight guy so these are suggestions:
Use the KeyDown/KeyUp events to capture changes to your text box.
Use the FocusManager to manage synchronous GotFocus/LostFocus events and check for changes there.