Close DropDown of RibbonComboBox on Button Click - c#

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;

Related

Extended WPF Toolkit DataGridControl with NavigationCommands.Refresh

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.

WPF ignore clicks outside of popup

In my WPF app I want to show a popup when I click a button.
If I click outside the popup, I want the popup to be closed. I can accomplish this by setting StaysOpen=False on the popup.
But when I click outside the popup, I want WPF to ignore the initial click that closes the popup. For example, if I click outside the popup on another button, I don't want that button to execute the click method.
How can I make WPF ignore the click outside the popup while it's open?
Here is some sample code. The popup opens when I click the "Popup" button, and it closes when I click outside. But I can click the "PrintMessage" button while the popup is open and its click event will fire. I would like its click event not to fire.
<Window x:Class="Test.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.Resources>
<Popup x:Key="pop" StaysOpen="False" Placement="MousePoint">
<UniformGrid Background="Red">
<Button>Btn1</Button>
<Button>Btn2</Button>
</UniformGrid>
</Popup>
</Window.Resources>
<UniformGrid>
<Button Click="Popup_Click">Popup</Button>
<Button Click="PrintMessage_Click">PrintMessage</Button>
</UniformGrid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Popup_Click(object sender, RoutedEventArgs e)
{
Popup pop = (Popup)Resources["pop"];
pop.IsOpen = true;
}
private void PrintMessage_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Test");
}
}

WPF image's gotfocus/lostfocus event does not fired

Could You please help me, why GotFocus and LostFocusa event doesn't fired when I Click to image and then to textbox?
My XAML:
<Window x:Class="imageclick.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>
<StackPanel>
<Image Source="Untitled.png" GotFocus="GF" LostFocus="LF" Focusable="True"></Image>
<TextBox ></TextBox>
</StackPanel>
</Grid>
</Window>
I could not understand why GotFocus/LostFocus event never fired
Thanks in advance
Update: When I set the tabindex, when the tab reached the image event fired, but I could not reach with mouse click
Image isn't a Control. Only Controls can get focus.Instead of GotFocus and LostFocus use MouseEnter and MouseLeave events,
<StackPanel>
<Image Stretch="Uniform" Source="Untitled.png" Height="410" MouseEnter="Image_MouseEnter" MouseLeave="Image_MouseLeave"></Image>
<TextBox Height="65"></TextBox>
</StackPanel>
According to MSDN, UIElement.GotFocus event occurs when this element gets logical focus.
And logical focus differs from keyboard focus, it is raised when the value of the IsFocused property of an element in the route is changed from false to true.
So, in order to achieve it through mouse clicks, need to handle the respective mouse button events or simply handle MouseDown and set the focus to the sender.
private void Image_MouseDown(object sender, MouseButtonEventArgs e)
{
if (sender is Image)
{
(sender as Image).Focus();
}
}
This will set the IsFocused property of the Image to true.

Get Keyboard events back, after WebBrowser gets focus

I have a situation where I would want to use WFP WebBrowser, but when the user presses a button something happens; however after WebBrowser gets focus, some keyboard and mouse events no longer fire in my app.
To reproduce: Create a new project, set XAML:
<Window x:Class="ProblemKeyboard.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>
<WebBrowser x:Name="browser" Height="177" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="479" />
</Grid>
</Window>
and let the codebehide override OnKeyDown() event.
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
browser.Navigate("http://www.google.com");
//The above line causes browser to focus
//and as a consequence the OnKeyDown() handler
//doesn't get called again
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Enter) MessageBox.Show("Yey!");
base.OnKeyDown(e);
}
}
Okay, understandably the user might want to type his Google query. But at some point I want to get control back. To this end, I've devised a button. When you click this button I want keyboard control to come back to the WPF app. But no matter what the button does, I can't get OnKeyDown() to fire again.
My particular restrictions allow WebBrowser to be destroyed at this point. I tried clearing its parent container, tried calling Dispose() and the garbage collector. Tried Focus()ing on things that have that functionality. Nothing seems to get control back.
I'd rather avoid solutions which create new Window() or something to that effect.
EDIT
I've found that putting a TextBox and making it focus gets me back focus! However I have no textboxes in my window, and adding one just for giggles seems counter-intuitive at best.
EDIT 2
Current temporary solution puts an invisible (well, kinda, it's just 0 by 0, Visibility.Hidden doesn't work) TextBox - enables it, focuses it and disables it. Without disabling it first some keys are handled by TextBox instead of bubbling up to KeyDown().
Yes it is reproducible for Enter key only and the fix is to use OnKeyUp() for Enter Key....
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.Key == Key.Enter) MessageBox.Show("Hi");
base.OnKeyUp(e);
}

WPF Listbox style with a button

I have a ListBox that has a style defined for ListBoxItems. Inside this style, I have some labels and a button. One that button, I want to define a click event that can be handled on my page (or any page that uses that style). How do I create an event handler on my WPF page to handle the event from my ListBoxItems style?
Here is my style (affected code only):
<Style x:Key="UsersTimeOffList" TargetType="{x:Type ListBoxItem}">
...
<Grid>
<Button x:Name="btnRemove" Content="Remove" Margin="0,10,40,0" Click="btnRemove_Click" />
</Grid>
</Style>
Thanks!
Take a look at RoutedCommands.
Define your command in myclass somewhere as follows:
public static readonly RoutedCommand Login = new RoutedCommand();
Now define your button with this command:
<Button Command="{x:Static myclass.Login}" />
You can use CommandParameter for extra information..
Now last but not least, start listening to your command:
In the constructor of the class you wish to do some nice stuff, you place:
CommandBindings.Add(new CommandBinding(myclass.Login, ExecuteLogin));
or in XAML:
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static myclass.Login}" Executed="ExecuteLogin" />
</UserControl.CommandBindings>
And you implement the delegate the CommandBinding needs:
private void ExecuteLogin(object sender, ExecutedRoutedEventArgs e)
{
//Your code goes here... e has your parameter!
}
You can start listening to this command everywhere in your visual tree!
Hope this helps
PS You can also define the CommandBinding with a CanExecute delegate which will even disable your command if the CanExecute says so :)
PPS Here is another example: RoutedCommands in WPF
As Arcturus posted, RoutedCommands are a great way to achieve this. However, if there's only the one button in your DataTemplate then this might be a bit simpler:
You can actually handle any button's Click event from the host ListBox, like this:
<ListBox Button.Click="removeButtonClick" ... />
Any buttons contained within the ListBox will fire that event when they're clicked on. From within the event handler you can use e.OriginalSource to get a reference back to the button that was clicked on.
Obviously this is too simplistic if your ListBoxItems have more than one button, but in many cases it works just fine.
You could create a user control (.ascx) to house the listbox. Then add a public event for the page.
Public Event btnRemove()
Then on the button click event in the usercontrol
RaiseEvent btnRemove()
You can also pass objects through the event just like any other method. This will allow your user control to tell your page what to delete.

Categories

Resources