Simple keyboard shortcut to activate button click event - c#

I have a very simple WPF application which has a button:
<Button x:Name="buttonNextImage" Content=">" Margin="0,0,0.4,-0.2"
Click="buttonNextImage_Click" HorizontalAlignment="Right" Width="25"
Background="Transparent"
BorderThickness="0">
</Button>
All I want to do is allow the user to activate this button's click event by pressing the right arrow key on their keybaord while the application window is in focus.
I checked this answer, but I don't have a label to add an underscore to - the only text I want the button to display is a > - surely it is possible to achieve this without resorting to adding a label.
I also tried the answer here but I just get this annoying error in my xaml saying MyCommand does not exist, even though I delcared it in the code-behind.
Any guidance on this is much appreciated..

You can implement <CommandBindings> and <InputBindings>:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.InputBindings>
<KeyBinding Key="Right"
Command="{Binding MessageCommand}"
CommandParameter="You pressed 'Right Arrow'"/>
</Window.InputBindings>
<Grid>
<Button Margin="45" Command="{Binding MessageCommand}">Click Me</Button>
</Grid>
</Window>
Code behind:
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 WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyDataContext();
}
public class MessageCommand : ICommand
{
public void Execute(object parameter)
{
string msg;
if (parameter == null)
msg = "Button Clicked!";
else
msg = parameter.ToString();
MessageBox.Show(msg);
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
public class MyDataContext
{
ICommand _messageCommand = new MessageCommand();
public ICommand MessageCommand
{
get { return _messageCommand; }
}
}
}
}
Here is the list of Keys: https://msdn.microsoft.com/en-us/library/system.windows.input.key(v=vs.100).aspx

Alternatively to KeyDown event (my previous suggestion), you could use ready baked-in ComponentCommands.MoveRight command. You can press > key or button. Here's the usage (note: there's even no need in InputBindings!):
XAML
<Window x:Class="WPFApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.CommandBindings>
<CommandBinding Command="ComponentCommands.MoveRight" Executed="OnMoveRight"/>
</Window.CommandBindings>
<StackPanel>
<Button Content=">" Command="ComponentCommands.MoveRight"/>
</StackPanel>
</Window>
C#
private void OnMoveRight(object sender, ExecutedRoutedEventArgs e)
{
// Do something with image
MessageBox.Show("Either button or '>' key was pressed");
}

I went with JohnyL's solution in the comments like this:
<Window KeyDown="OnKeyDownHandler">
code behind
private void OnKeyDownHandler(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Right:
NextImage();
break;
case Key.Left:
PreviousImage();
break;
default:
break;
}
}
Nice and simple, but it is a shame WPF doesn't just have an easy way of doing this built in to its controls.

Related

WPF dragblz Finding TabItem to Re-Add

ok Im not sure if this issue is related to the library or me being still being new to WPF .but , I'm using the dragablz library and I am trying to re-add a tab after tearing it then closing that specfic window. However , I cant seem to find all the TabItem when ever I try to search for it in the grid of the current winodw I get nothing , this what I treid.
<Window x:Class="TeheMan8_Editor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TeheMan8_Editor"
xmlns:dragablz="http://dragablz.net/winfx/xaml/dragablz"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<dragablz:TabablzControl Name="tabHub" AllowDrop="True" Grid.ColumnSpan="2">
<dragablz:TabablzControl.InterTabController>
<dragablz:InterTabController />
</dragablz:TabablzControl.InterTabController>
<TabItem Name="mainTab" Header="Tab No. 1" IsSelected="True">
<Button Click="Button_Click">Open FileButton</Button>
</TabItem>
</dragablz:TabablzControl>
</Grid>
</Window>
CSharp Code:
using DiscUtils.Iso9660;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace TeheMan8_Editor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var items = this.grid.Children.OfType<TabItem>(); //returns Empty
}
}
}
never mind I figured it out , the TabablzControl Object has a OfType function for the "Items.SouceCollection" property

C# WPF Prism Page connect

I try to connect a page to my main window using WPF app .net framework and Prism framework.
What am I missing here?
App.xaml:
<prism:PrismApplication x:Class="Aplicatie2._0.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:Aplicatie2._0">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
App.xaml.cs:
using Prism.Modularity;
using Prism.Ioc;
using System.Windows;
using System.ComponentModel;
using Prism.Unity;
using Aplicatie2._0.View;
namespace Aplicatie2._0
{
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainPage>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MainPage>("MainPage");
containerRegistry.RegisterForNavigation<FirstQ>("FirstQ");
}
}
}
ViewModel->MainPageViewModel:
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Commands;
using System.Windows.Input;
using System.Windows;
using Prism.Regions;
using Aplicatie2._0.View;
namespace Aplicatie2._0.ViewModel
{
class MainPageViewModel : BindableBase
{
private string _Title = "Test";
private IRegionManager _regionManager;
public string Title
{
get
{
return _Title;
}
set
{
SetProperty(ref _Title, value);
}
}
public DelegateCommand PressButton { get; private set; }
public MainPageViewModel(IRegionManager regionManager)
{
PressButton = new DelegateCommand(Execute);
_regionManager = regionManager;
}
public void Execute()
{
MessageBox.Show("TEST");
_regionManager.RequestNavigate("MainContent", "FirstQ");
}
}
}
View->MainPage:
<Window x:Class="Aplicatie2._0.View.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:VM="clr-namespace:Aplicatie2._0.ViewModel"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:Aplicatie2._0.View"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="{Binding Title}" Height="450" Width="800">
<Window.DataContext>
<VM:MainPageViewModel/>
</Window.DataContext>
<Grid>
<ContentControl prism:RegionManager.RegionName="MainContent"/>
<Button Content="Button" CommandParameter="FirstQ" HorizontalAlignment="Left" Margin="151,54,0,0" VerticalAlignment="Top" Width="75" Command="{Binding PressButton}"/>
</Grid>
</Window>
View->FirstQ
<Page x:Class="Aplicatie2._0.View.FirstQ"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Aplicatie2._0.View"
Background="White"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="FirstQ">
<Grid>
<TextBlock HorizontalAlignment="Left" Margin="249,108,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
</Grid>
</Page>
My window does not start. If I make MainPageViewModel constructor like this:
public MainPageViewModel()
window is open.
If I don't have:
<Window.DataContext>
<VM:MainPageViewModel/>
</Window.DataContext>
my bind's not work, whether I have or not
prism:ViewModelLocator.AutoWireViewModel="True"...
What did I miss?
You either have to
align the namespaces with the default convention (MyApp.Views for the views, MyApp.ViewModels for the view models)
register view and view model together
create your own convention to link the views' and view models' types
so that the ViewModelLocator can do his work.
From the code you posted, Aplicatie2._0.View.MainPage should be Aplicatie2._0.Views.MainPage and Aplicatie2._0.ViewModel.MainPageViewModel should be Aplicatie2._0.ViewModels.MainPageViewModel.

How to trigger a method in a XAML element when a textproperty changes

I really don't know how to search to find a solution to this (I googled a lot, maybe I'm blind...).
I have a ComboBox which also contains a TextBox. The ComboBox is instantiated in a separate Control.xaml with a specific DataContext, where it gets its content for the Popup list.
Now when I type something into the TextBox, I want to trigger a method which then filters the list of my DataContext for the specific elements.
So my ComboBox.cs has some of the following content:
public event EventHandler FilterTextChanged;
protected virtual void OnFilterTextChanged(EventArgs args)
{
FilterTextChanged?.Invoke(FilterText, args);
}
public string FilterText
{
get { return _filterText; }
set
{
//This point is reached when I type something into the TextBox within the ComboBox
if (_filterText == value) return;
_filterText = value;
OnFilterTextChanged(EventArgs.Empty);
OnPropertyChanged("FilterText");
}
}
And in my Control.xaml, I have configured it like this:
<my:ComboBox x:Name="FURecipeComboBox"
AuthorizationMode="IsEnabled"
IsTextSearchEnabled="False"
StaysOpenOnEdit="True"
FilterTextChanged="FURecipeComboBox_OnFilterTextChanged"
ItemsSource="{Binding RecipeFileNames}"
SelectedItem="{Binding Value, Delay=100, ElementName=AlphaNumericTouchpadTextVarIn}"
d:DataContext="{d:DesignInstance {x:Type adapter:ToolRecipeVariableInfo}, IsDesignTimeCreatable=False}">
</my:ComboBox>
But I just can't get it to catch the event "FilterTextChanged", and my method "FURecipeComboBox_OnFilterTextChanged" will not be reached anytime...
I would be really really glad for some hints or help!
Kind regards
BB
Have a look at RoutedEvents at microsoft docs
This is a example post from Stackoverflow
In your case try to change EventHandler to RoutedEventHandler.
I made a small example:
Main.xaml
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:UserControl1 HorizontalAlignment="Left" Height="207" Margin="348,175,0,0" VerticalAlignment="Top" Width="311" MyClick="UserControl1_MyClick"/>
</Grid>
Main.cs
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UserControl1_MyClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("Yep");
}
}
}
control.cs
public partial class UserControl1 : UserControl
{
public event RoutedEventHandler MyClick;
public UserControl1()
{
InitializeComponent();
}
private void textBox_KeyDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Enter)
{
if (MyClick != null)
MyClick(this, new RoutedEventArgs());
}
}
}
control.xaml
<UserControl x:Class="WpfApp1.UserControl1"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
d:DesignHeight="372.313" d:DesignWidth="350">
<Grid>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="218" Margin="59,54,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="202" KeyDown="textBox_KeyDown"/>
</Grid>

WPF Tooltip that works with touch

I have a WPF application where tooltip is bound to a viewmodel, and all is great when I hover over my control and wait for the tooltip.
To support mouseless devices, I would like to show the same tooltip, when "clicking" my control.
If I implement a MouseDown handler that sets the tooltip's IsOpen = true, the tooltip is shown, but binding has not been evaluated, unless I hover and wait first.
XAML:
<Window x:Class="TooltipApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TooltipApplication"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Image Source="http://www.brockmann-consult.de/beam/doc/help/visat/images/icons/Help22.png" MouseDown="Image_MouseDown" Stretch="None" MouseLeave="Image_MouseLeave">
<Image.ToolTip>
<ToolTip>
<TextBlock Text="{Binding Hint}"/>
</ToolTip>
</Image.ToolTip>
</Image>
</Grid>
</Window>
Code behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TooltipApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public string Hint { get { return "This is my hint"; } }
private void Image_MouseDown(object sender, MouseButtonEventArgs e)
{
var tooltip = (sender as FrameworkElement).ToolTip;
if (tooltip is ToolTip)
((ToolTip)tooltip).IsOpen = true;
}
private void Image_MouseLeave(object sender, MouseEventArgs e)
{
var tooltip = (sender as FrameworkElement).ToolTip;
if (tooltip is ToolTip)
((ToolTip)tooltip).IsOpen = false;
}
}
}
Using the code above, click the image before the tooltip timer elapses, or run it on a touch device.
Placing a breakpoint in the Hint getter also proves, that it is not called unless you wait for the tooltip timer.
How can I force the tooltip to evaluate its binding, and then show?

Cascaded command bindings possible

I have a MainWindow that contains multiple views using MVVM. In fact the MainWindow holds only a list of Models and each time a Model is added it creates a View (here a UserControl) and associates the DataContext (Model) to the View. Each view is put into a separate TabItem in a TabControl.
The Model itself has a CommandBindingsCollection and assigns this command bindings to the View. This means that for example F10 is available multiple times, but should only the active View should react on F10.
But, F10 does not work at all. Only if I assign the CommandBinding to the MainWindow it works, but this makes the View dependent on the UserControl and this is not what I want, since I wnat to create the View as independent as possible from the MainWindow.
The only solution I have is to make this dynamically intercepting the change of the current TabItem and add/remove the commands for the active View. Currently everything works without code, but then I have to write code for it.
Attached is a code of the MainWindow:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
</Window>
using System.Windows;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PluginControl aControl = new PluginControl();
Content = aControl;
}
}
}
and the code of the UserControl:
<UserControl x:Class="WpfApplication3.PluginControl"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Background="White">
<StackPanel>
<Button Command="{Binding myCommand}" Content="PushMe" Focusable="False"/>
<Label Content="Nothing pressed" Name="myLabel"/>
</StackPanel>
</UserControl>
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for PluginControl.xaml
/// </summary>
public partial class PluginControl : UserControl
{
public RoutedCommand myCommand
{
get;
private set;
}
public PluginControl()
{
InitializeComponent();
DataContext = this;
myCommand = new RoutedCommand();
myCommand.InputGestures.Add(new KeyGesture(Key.F10));
CommandBindings.Add(new CommandBinding(myCommand, myCommandHandler));
}
private void myCommandHandler(object sender, ExecutedRoutedEventArgs executed)
{
myLabel.Content = DateTime.Now.ToString();
}
}
}
As you see I have set the Button to Focusable false, since I want to have the command working in general, not only when the button is focused. I'm I missing something or thinking in a wrong direction, that making adding a CommandBinding does not implicitly mean that the command does work without binding it?
Adding the Command to the MainWindow itself works.
Any help?

Categories