WPF Shortcut Key not firing - wpf

I have a prism delegate command setup for refresh the data in my application.
I also have setup shortcuts for close and about window using delegate command.
Using F5 also does not trigger the refresh in the view model. If I use Alt+F4, the application closes. But it does not execute the CloseApplication method in the view model. What is missing in the following code to execute the ViewModel using the Gesture Shorcuts?
UserControl:
<UserControl.InputBindings>
<KeyBinding Gesture="ALT+F4" Command="{Binding CloseCommand}" />
<KeyBinding Gesture="F5" Command="{Binding RefreshCommand}" />
</UserControl.InputBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="E_xit" Command="{Binding CloseCommand}" InputGestureText="Alt+F4" />
<MenuItem Header="Refresh" Command="{Binding RefreshCommand}" InputGestureText="F5" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About" Command="{Binding AboutCommand}" />
</MenuItem>
</Menu>
<ToolBar ToolBarTray.IsLocked="True">
<Button Content="Home" MinHeight="50" MinWidth="80" VerticalContentAlignment="Bottom" />
<Button Content="Page 1" MinHeight="50" MinWidth="80" VerticalContentAlignment="Bottom" />
<Button Content="Page 2" MinHeight="50" MinWidth="80" VerticalContentAlignment="Bottom" />
</ToolBar>
</DockPanel>
ViewModel of the UserControl
public class TopMenuViewModel:NotificationObject
{
private DelegateCommand _closeCommand;
private DelegateCommand _aboutCommand;
private DelegateCommand _refreshCommand;
public TopMenuViewModel()
{
_closeCommand = new DelegateCommand(CloseApplication);
_aboutCommand = new DelegateCommand(ShowAboutWindow);
_refreshCommand = new DelegateCommand(RefreshApplication);
}
private void ShowAboutWindow()
{
Console.WriteLine("Show about window");
}
private void CloseApplication()
{
Application.Current.Shutdown();
}
private void RefreshApplication()
{
Console.WriteLine("Refreshing..");
}
public ICommand CloseCommand
{
get { return _closeCommand; }
}
public ICommand AboutCommand
{
get { return _aboutCommand; }
}
public ICommand RefreshCommand
{
get { return _refreshCommand; }
}
}
The view model methods are called if I use the mouse to click the menu or use the Alt+x or Alt+A. But not using the KeyBinding that I have put in. Thanks for your help.

Related

Relay Command not firing on menu item click

My View
<Button.ContextMenu>
<ContextMenu x:Name="Conn_Context_button" Style="{StaticResource LeftContextMenuStyle}">
<MenuItem Style="{StaticResource LeftContextMenuItemStyle}" Header="{x:Static properties:ResourceWrapper.Dashboard_Connection_Delete}" Click="MenuItem_DeleteConnection_Click" />
<MenuItem Style="{StaticResource LeftContextMenuItemStyle}" Header="{x:Static properties:ResourceWrapper.Dashboard_Connection_Refresh}" Command="{Binding MyViewModel.RefreshCommand}" />
</ContextMenu>
MyViewModel.cs
public RelayCommand RefreshCommand { get; set; }
RefreshCommand = new RelayCommand(RefreshConnection);
private void RefreshConnection(object sender)
{
//My Logic
}
Here RefreshCommand is not firing when i click the refresh menu item
As a good example, take a look to this situation.
Here's a simple piece of code taken from one of my current projets:
private void PrepareCommands()
{
RefreshCommand = new RelayCommand(RefreshCommandMethod);
AddConfigurationCommand = new RelayCommand(AddConfigurationCommandMethod, param => CanAddConfiguration);
EditConfigurationCommand = new RelayCommand(EditConfigurationCommandMethod, param => CanEditConfiguration);
RemoveConfigurationCommand = new RelayCommand(RemoveConfigurationCommandMethod, param => CanRemoveConfiguration);
}
where the commands are
#region Commands
public ICommand AddConfigurationCommand { get; set; }
public ICommand EditConfigurationCommand { get; set; }
public ICommand RemoveConfigurationCommand { get; set; }
public ICommand RefreshCommand { get; set; }
#endregion
Bindings are
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" DockPanel.Dock="Right">
<Button Template="{StaticResource AddButton}" Command="{Binding AddConfigurationCommand}" Margin="3,0" />
<Button Template="{StaticResource EditButton}" Command="{Binding EditConfigurationCommand}" Margin="3,0" />
<Button Template="{StaticResource DeleteButton}" Command="{Binding RemoveConfigurationCommand}" Margin="3,0" />
</StackPanel>
As Jan Walczak said above, try to use ICommand instead of RelayCommand. If you have created your own RelayCommand, don't forget to inherit from ICommand.

TextEdit_KeyDown Event binding to a command

I have a TextEdit and a Button like this :
<dxe:TextEdit Text="{Binding SearchText}" Width="200" Height="25" VerticalAlignment="Center" KeyDown="TextEdit_KeyDown" />
<Button Command="{Binding SearchCommand}" VerticalAlignment="Center" Margin="20,0,0,0" >
When user clicks the button, SearchCommand works successfully and returns resulsts. I want same thing to happen when user pressses Enter. How can I bind TextEdit_KeyDown event to a command so that I get the same result.
Take a look at the EventToCommand behavior from DevExpress MVVM Framework:
View:
<UserControl ...
DataContext="{dxmvvm:ViewModelSource Type=local:SearchViewModel}">
//...
<dxe:TextEdit Text="{Binding SearchText}" Width="200" Height="25" VerticalAlignment="Center">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="KeyDown"
Command="{Binding SearchByKeyCommand}"
PassEventArgsToCommand="True"
>
</dxmvvm:Interaction.Behaviors>
</dxe:TextEdit>
<Button Command="{Binding SearchCommand}" VerticalAlignment="Center" Margin="20,0,0,0" >
//...
ViewModel:
[POCOViewModel]
public class SearchViewModel {
public virtual SearchText {
get ;
set;
}
public void Search() {
//...
}
public void SearchByKey(KeyEventArgs) {
Search();
}
public bool CanSearchByKey(KeyEventArgs args) {
return (args.KeyCode == Keys.Enter) && !string.IsNullOrEmpty(SearchText);
}
}
if (e.KeyCode == Keys.Enter)
{
//Do your stuff
}
e is the EventArg which is always transmitted when calling so you have to see what is transmitted in the variable

Navigating from one screen to another in Caliburn

I am using a sample from http://www.mindscapehq.com/blog/index.php/2013/09/11/caliburn-micro-part-6-introduction-to-screens-and-conductors/
There is an AppViewModel in which other ViewModels are activated by calling ActivateItem.
The sample is working for me: I can see the corresponding View.
I now want to activate a ViewModel from another ViewModel. It gets instantiated but the corresponding View is not displayed.
How can I activate "GreenScreenViewModel" from "RedScreenViewModel"?
AppView:
<UserControl x:Class="CaliburnMicroApp_Navigation.AppView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<DockPanel Background="LightBlue" MinHeight="400" MinWidth="400">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" HorizontalAlignment="Center">
<Button x:Name="ShowRedScreen" Content="Red" Width="50" />
<Button x:Name="ShowGreenScreen" Content="Green" Width="50" Margin="12,0,0,0" />
<Button x:Name="ShowBlueScreen" Content="Blue" Width="50" Margin="12,0,0,0" />
</StackPanel>
<ContentControl x:Name="ActiveItem" />
</DockPanel>
</UserControl>
AppViewModel
public class AppViewModel : Conductor<object>
{
public void ShowRedScreen()
{
ActivateItem(new RedViewModel());
}
public void ShowGreenScreen()
{
ActivateItem(new GreenViewModel());
}
public void ShowBlueScreen()
{
ActivateItem(new BlueViewModel());
}
}
RedViewModel - this does not display GreenView ()
public class RedViewModel : Conductor<object>
{
public void DisplayGreen()
{
ActivateItem(new GrenViewModel());
}
}
RedView
<Grid Background="Red">
<StackPanel>
<TextBlock Text="red" FontSize="48" FontWeight="Bold" Foreground="#3CA527" />
<Button Name="DisplayGreen">
<TextBlock >Next Screen</TextBlock>
</Button>
</StackPanel>
</Grid>
If you want the ActiveItem displayed in the ContentControl of your AppView to change when you press your Button in RedViewModel, you will need to use the EventAggregator to pass a message from your RedViewModel to your AppViewModel.
Mindscape EventAggregator tutorial

Change button image when context menu item is selected

Can anyone tell me how to change button image when context menu Item is clicked?
I have a button with image and context menu in it. I want to change the image of the button, everytime I click contextmenu item.
With the following piece of code I am able to display contextmenu items on right click. But don't know how to proceed further.
Can anyone guide me ?
I tried using command strangely command never got called.
<Button Background="Gray" Name="statusBtn" VerticalAlignment="Top" HorizontalAlignment="Right" FontWeight="Bold" Foreground="Red">
<DockPanel >
<Image DockPanel.Dock="Top" Stretch="Fill" Source="{Binding ToEnum, Converter={StaticResource EnumToImgConverter}}" Height="37" Width="72" />
<TextBlock HorizontalAlignment="Center" Margin="0,23,1,2">Test</TextBlock>
</DockPanel>
<Button.ContextMenu>
<ContextMenu Name="ContextMenuName" ItemsSource="{Binding Path=Popuplistitems}">
<ContextMenu.ItemTemplate >
<DataTemplate DataType="MenuItem">
<MenuItem Header="{Binding Message}" Command="{Binding popupListCommand}">
<MenuItem.ItemContainerStyle >
<Style TargetType="MenuItem">
<Setter Property="IsCheckable" Value="True"/>
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</Button.ContextMenu>
</Button>
First, I think you need to change your MenuItem.ItemContainerStyle to just MenuItem.Style - I believe the ItemContainerStyle is meant for the sub-menuitems that you can place into the MenuItem when you want nested context menus.
I was able to get the content of the button to change with the following code. I used text content, but it should be easy to swap it out for image content:
The xaml:
<Window x:Class="ChangeButtonContent.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 Height="30" Width="200">
<Button.Content>
<DockPanel >
<TextBlock Text="{Binding ChangingText, Mode=TwoWay}" />
</DockPanel>
</Button.Content>
<Button.ContextMenu>
<ContextMenu Name="ContextMenuName">
<MenuItem Command="{Binding ChangeTextCommand}" Header="ChangeText"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
The Code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
ChangingText = "Initial Text";
ChangeTextCommand = new MyCommand((notUsed) =>
{
ChangingText = "Text After Context Menu Click";
});
}
private string _changingText;
public string ChangingText
{
get
{
return _changingText;
}
set
{
_changingText = value;
OnPropertyChanged("ChangingText");
}
}
public MyCommand ChangeTextCommand
{
get;
private set;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyCommand : ICommand
{
private Action<object> _action;
public MyCommand(Action<object> action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter);
}
}

How to open a popup menu when a button is clicked?

I have a button with an Image as its content in a toolbar. I would like this button to open a menu beneath it when clicked. How?
<Toolbar>
<Button>
<Button.Content>
<Image Source="../Resources/help.png"></Image>
</Button.Content>
</Button>
</Toolbar>
Thanks!!
Instead of using a subclassed Button, you can use Attached Properties or a Behavior to implement the drop down button functionality, for a more WPF-like approach and so you don't impact the button style:
using System.Windows.Interactivity;
public class DropDownButtonBehavior : Behavior<Button>
{
private bool isContextMenuOpen;
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.AddHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click), true);
}
void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
{
Button source = sender as Button;
if (source != null && source.ContextMenu != null)
{
if (!isContextMenuOpen)
{
// Add handler to detect when the ContextMenu closes
source.ContextMenu.AddHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed), true);
// If there is a drop-down assigned to this button, then position and display it
source.ContextMenu.PlacementTarget = source;
source.ContextMenu.Placement = PlacementMode.Bottom;
source.ContextMenu.IsOpen = true;
isContextMenuOpen = true;
}
}
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click));
}
void ContextMenu_Closed(object sender, RoutedEventArgs e)
{
isContextMenuOpen = false;
var contextMenu = sender as ContextMenu;
if (contextMenu != null)
{
contextMenu.RemoveHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed));
}
}
}
Usage:
<!-- NOTE: xmlns:i="schemas.microsoft.com/expression/2010/interactivity‌​" -->
<Button>
<i:Interaction.Behaviors>
<local:DropDownButtonBehavior/>
</i:Interaction.Behaviors>
<Button.Content>
<StackPanel Orientation="Horizontal">
<Image Source="/DropDownButtonExample;component/Assets/add.png" SnapsToDevicePixels="True" Height="16" Width="16" />
<TextBlock Text="Add"/>
<Separator Margin="2,0">
<Separator.LayoutTransform>
<TransformGroup>
<TransformGroup.Children>
<TransformCollection>
<RotateTransform Angle="90"/>
</TransformCollection>
</TransformGroup.Children>
</TransformGroup>
</Separator.LayoutTransform>
</Separator>
<Path Margin="2" VerticalAlignment="Center" Width="6" Fill="#FF527DB5" Stretch="Uniform" HorizontalAlignment="Right" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "/>
</StackPanel>
</Button.Content>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Attribute"/>
<MenuItem Header="Setting"/>
<Separator/>
<MenuItem Header="Property"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
Current gist source and example here.
If you have the luxury of targeting .NET 4 or newer, the new Ribbon library has a RibbonMenuButton that can do this. In 4.5 it is as easy as referencing System.Windows.Controls.Ribbon in your project:
<RibbonMenuButton x:Name="ExampleMenu" SmallImageSource="/Images/Example.png">
<RibbonMenuItem x:Name="ExampleMenuItem" Header="Save" />
</RibbonMenuButton>
i found this two solutions after searching for it:
1) Split Button in WPF
2) DropDownButtons in WPF
the second solution is my favorit (source taken from the website by Andrew Wilkinson)
public class DropDownButton : ToggleButton
{
// *** Dependency Properties ***
public static readonly DependencyProperty DropDownProperty =
DependencyProperty.Register("DropDown",
typeof(ContextMenu),
typeof(DropDownButton),
new UIPropertyMetadata(null));
// *** Constructors ***
public DropDownButton() {
// Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property
Binding binding = new Binding("DropDown.IsOpen");
binding.Source = this;
this.SetBinding(IsCheckedProperty, binding);
}
// *** Properties ***
public ContextMenu DropDown {
get { return (ContextMenu)this.GetValue(DropDownProperty); }
set { this.SetValue(DropDownProperty, value); }
}
// *** Overridden Methods ***
protected override void OnClick() {
if (this.DropDown != null) {
// If there is a drop-down assigned to this button, then position and display it
this.DropDown.PlacementTarget = this;
this.DropDown.Placement = PlacementMode.Bottom;
this.DropDown.IsOpen = true;
}
}
}
usage
<ctrl:DropDownButton Content="Drop-Down">
<ctrl:DropDownButton.DropDown>
<ContextMenu>
<MenuItem Header="Item 1" />
<MenuItem Header="Item 2" />
<MenuItem Header="Item 3" />
</ContextMenu>
</ctrl:DropDownButton.DropDown>
</ctrl:DropDownButton>
hope that helps you...
There are lots of ways to get this done and you might consider this approach...
<ToolBar DockPanel.Dock="Top">
<MenuItem IsSubmenuOpen="{Binding SomeProperty}">
<MenuItem.Header>
<Button Height="28">
<Button.Content>
<Image Source="---your image---"></Image>
</Button.Content>
</Button>
</MenuItem.Header>
<Menu>
<MenuItem Header="Do this" />
<MenuItem Header="Do that"/>
</Menu>
</MenuItem>
</ToolBar>
This wraps your button into a MenuItem that has a submenu. As shown here, the MenuItem property called IsSubMenuOpen is bound to a notifying property of type bool in your ViewModel called SomeProperty.
You would have to have your ViewModel toggle this property depending upon what you are actually trying to do. You may want to consider making your button a toggle button so as to facilitate closing the submenu, otherwise you'll have to wire up additional behaviour in your ViewModel.

Resources