I have a MainWindow in my application. The MainWindow hosts a UserControl in its ContentControl(I call this MainPage). MainPage goes onto hosts another UserControl which contains all sorts of controls on it (KiviPage).
I am trying to connect to a database in MainPage and load a file in the KiviPage. If any of the two operations fail (connection to database or file loading) I have to quit the application. Which means I have to quit the application from the user controls.
Whats the best way to do this?
Simply call "Shutdown" from code behind of the user control:
Application.Current.Shutdown();
I think, you may implement this action through a attached DependencyProperty. Something like that (it's a simple work example):
XAML
<Window x:Class="ShutdownAppHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ShutdownAppHelp"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="local:ProgramBehaviours.Shutdown" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<CheckBox Content=" Shutdown" IsChecked="False" />
</Grid>
</Window>
Code behind
namespace ShutdownAppHelp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public static class ProgramBehaviours
{
// Shutdown program
public static void SetShutdown(DependencyObject target, bool value)
{
target.SetValue(ShutdownProperty, value);
}
public static readonly DependencyProperty ShutdownProperty =
DependencyProperty.RegisterAttached("Shutdown",
typeof(bool),
typeof(ProgramBehaviours),
new UIPropertyMetadata(false, OnShutdown));
// Here call function in UIPropertyMetadata()
private static void OnShutdown(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool && ((bool)e.NewValue))
{
Application.Current.Shutdown();
}
}
}
}
You can put any kind of behavior in DependencyProperty, which is available only through the code and call it a XAML:
<DataTrigger Binding="{Binding ElementName=SomeControl, Path=Tag}" Value="Shutdown">
<Setter Property="local:ProgramBehaviours.Shutdown" Value="True" />
</DataTrigger>
Also, you can access it directly through the code of behavior:
ProgramBehaviours.SetShutdown(SomeControl, Value);
Or from XAML without condition:
<SomeControl local:ProgramBehaviours.SetShutdown="True" ... />
Related
I implemented a user control with a dependency property that looks like this:
public partial class MyUC : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new FrameworkPropertyMetadata(Brushes.White,
FrameworkPropertyMetadataOptions.AffectsRender));
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
//...
}
and try to set this property in XAML as follows:
<UserControl x:Class="Custom.MyUC"
x:Name="myUCName"
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:Custom"
mc:Ignorable="d"
TabIndex="0" KeyboardNavigation.TabNavigation="Local"
HorizontalContentAlignment="Left" VerticalContentAlignment="Top"
MouseLeftButtonDown="OnMouseLeftButtonDown">
<UserControl.Style>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Black"/>
</Style>
</UserControl.Style>
<Border BorderThickness="0">
//...
</Border>
</UserControl>
It compiles but when I run the app I get the following exception:
Set property 'System.Windows.Setter.Property' threw an exception.'
Line number '..' and line position '..'."
How can I solve this?
The problem arises because you're trying to apply a style with TargetType="MyUC" to an element of type UserControl.
The solution is to apply the style from outside of the control. So for example when you use the control in another window:
<Window.Resources>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<local:MyUC />
</Grid>
As a test I added this code to the user control:
public partial class MyUC
{
public MyUC()
{
InitializeComponent();
}
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new PropertyMetadata(Brushes.White, PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
((MyUC)dependencyObject).MyBackgroundPropertyChanged(
(Brush)dependencyPropertyChangedEventArgs.NewValue);
}
private void MyBackgroundPropertyChanged(Brush newValue)
{
Background = newValue;
}
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
}
Which then results in the control having a red background.
Hope someone can enlighten me on the best mvvm practice using service locator.
Base principles are clear. I have my views with corresponding view model, everything works at it should.
Lets make a simple example. I have one main window and 2 user controls UCA and UCB. Each of them have view model registered in the locator class.
Using this IoC pattern how can you display UCA and UCB in the main window using one content control and binding through main window view model? To be precise I want to show only one control at the same time. I can't bind the UCA or UCB view model because this is view first approach, the view is not automatically resolved.
What is the correct approach for this?
Thanks
You can create a separate service for launching views as dialog, so that it can be used in a generic way across the application. And will inject this service to the ViewModel via Constructor which wants to launch any dialog.
public interface IDialogService<T>
{
void Show();
void ShowDialog();
}
public class DialogService<T> : IDialogService<T> where T : Window
{
public void Show()
{
container.Resolve<T>().Show();
}
public void ShowDialog()
{
container.Resolve<T>().ShowDialog();
}
}
Now just inject this service to the respective viewmodel.
public class YourViewModel
{
//commands
public ICommand someCommand { get; set; }
private IDialogService<BookingView> _dialogService;
public YourViewModel(IDialogService<YourView > dialogService)
{
_dialogService = dialogService
someCommand = new RelayCommand(someCommandDoJob, () => true);
}
public void someCommandDoJob(object obj)
{
//Since you want to launch this view as dialog you can set its datacontext in its own constructor.
_dialogService.ShowDialog();
}
}
One solution could be using ContentTemplate property together with DataTrigger to selectively show UCA or UCB (see example below). UCA could also be set as default view in a style setter. In this case only one DataTriggers is needed.
Another solution could be using ContentTemplateSelector property and implement a DataTemplateSelector.
See: ContentControl.ContentTemplateSelector (MSDN)
<!--content control in main window-->
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<!--suppose main window view model has a bool property UseUCA-->
<!--if UseUCA is true render UCA view-->
<DataTrigger Binding="{Binding UseUCA}" Value="True">
<DataTrigger.Setters>
<!--by setting ContentTemplate property you control what is rendered inside of the content control-->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<!--render UCA view-->
<local:UCA />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
<!--if UseUCA is false render UCB view-->
<DataTrigger Binding="{Binding UseUCA}" Value="False">
<DataTrigger.Setters>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<!--render UCB view-->
<local:UCB />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
OK... here is a thought... you can keep track of the "currentview" in your MainViewModel and let the UI show the correct control based on type. Here is a quick example. I am using a Button to switch views... this could ideally be done via any logic that fits your requirements.
MainWindow:
<Window x:Class="WpfApplication4.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:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Content="Switch Views" Command="{Binding SwitchViewsCommand}" />
<ContentControl Grid.Row="1" Content="{Binding CurrentControl}">
</ContentControl>
</Grid>
</Window>
UCA and UCB are simply user controls with different text in them:
<UserControl x:Class="WpfApplication4.UserControls.UCA"
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:WpfApplication4.UserControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="This is user control A" />
</Grid>
</UserControl>
UCAViewModel and UCBViewModel are empty viewmodels in my example that inherit from ViewModelBase
namespace WpfApplication4.ViewModel
{
public class UCAViewModel : ViewModelBase
{
}
}
The MainViewModel handles the currently shown view based on its viewmodel
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Practices.ServiceLocation;
namespace WpfApplication4.ViewModel
{
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
RegisterCommands();
SwitchView();
}
private void SwitchView()
{
if(CurrentControl == null)
{
CurrentControl = ServiceLocator.Current.GetInstance<UCAViewModel>();
}
else
{
if(CurrentControl is UCAViewModel)
CurrentControl = ServiceLocator.Current.GetInstance<UCBViewModel>();
else
CurrentControl = ServiceLocator.Current.GetInstance<UCAViewModel>();
}
}
private ViewModelBase _currentControl;
public ViewModelBase CurrentControl
{
get { return _currentControl; }
set
{
if (_currentControl != value)
{
_currentControl = value;
RaisePropertyChanged("CurrentControl");
}
}
}
private void RegisterCommands()
{
SwitchViewsCommand = new RelayCommand(SwitchView);
}
public RelayCommand SwitchViewsCommand { get; private set; }
}
}
the ViewModelLocator stores the instances
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
namespace WpfApplication4.ViewModel
{
/// <summary>
/// This class contains static references to all the view models in the
/// application and provides an entry point for the bindings.
/// </summary>
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<UCAViewModel>();
SimpleIoc.Default.Register<UCBViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
}
And finally, the glue that makes the correct view show is done in the app.xaml file:
<Application x:Class="WpfApplication4.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication4" StartupUri="MainWindow.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:localUC="clr-namespace:WpfApplication4.UserControls"
xmlns:vm="clr-namespace:WpfApplication4.ViewModel">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<DataTemplate DataType="{x:Type vm:UCAViewModel}">
<localUC:UCA />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:UCBViewModel}">
<localUC:UCB />
</DataTemplate>
</Application.Resources>
</Application>
I implemented a user control with a dependency property that looks like this:
public partial class MyUC : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new FrameworkPropertyMetadata(Brushes.White,
FrameworkPropertyMetadataOptions.AffectsRender));
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
//...
}
and try to set this property in XAML as follows:
<UserControl x:Class="Custom.MyUC"
x:Name="myUCName"
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:Custom"
mc:Ignorable="d"
TabIndex="0" KeyboardNavigation.TabNavigation="Local"
HorizontalContentAlignment="Left" VerticalContentAlignment="Top"
MouseLeftButtonDown="OnMouseLeftButtonDown">
<UserControl.Style>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Black"/>
</Style>
</UserControl.Style>
<Border BorderThickness="0">
//...
</Border>
</UserControl>
It compiles but when I run the app I get the following exception:
Set property 'System.Windows.Setter.Property' threw an exception.'
Line number '..' and line position '..'."
How can I solve this?
The problem arises because you're trying to apply a style with TargetType="MyUC" to an element of type UserControl.
The solution is to apply the style from outside of the control. So for example when you use the control in another window:
<Window.Resources>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<local:MyUC />
</Grid>
As a test I added this code to the user control:
public partial class MyUC
{
public MyUC()
{
InitializeComponent();
}
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new PropertyMetadata(Brushes.White, PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
((MyUC)dependencyObject).MyBackgroundPropertyChanged(
(Brush)dependencyPropertyChangedEventArgs.NewValue);
}
private void MyBackgroundPropertyChanged(Brush newValue)
{
Background = newValue;
}
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
}
Which then results in the control having a red background.
I created an expander style that contains a checkbox in its header. The checkbox state is bound to an attached property:
<Style TargetType="{x:Type Expander}" x:Key="MyCheckboxExpander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
(...)
<CheckBox x:Name="ExpanderHeaderChk" VerticalAlignment="Center" Margin="4,0,0,2"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(my:AP.IsChecked)}" />
(...)
I my view, inside the expander I have a stackpanel with a ComboBox.
Whenever the user checks the expander's checkbox, I wan't that the combobox gets the first item selected, on the oher hand whenever the user unchecks it, I wan't that the selecteditem of the combobox be null.
How can I accomplish this? I'm following the MVVM pattern, but since this is more a matter of the view, I'm open to code-behind suggestions.
Well, I think your design is not optimal. You see, you are trying to change the semantics of the Expander. The real expander doesn't have the semantics with additional checkbox, so the control you are creating is not an Expander any more.
I would suggest that you switch to a user control (or maybe a custom control, look at your semantics), and expose the needed event in your control's class. The XAML for the user control should be perhaps an expander with a checkbox.
Edit: example with UserControl (not tested)
(XAML)
<UserControl x:Class="namespace:MyCheckboxExpander">
<Expander>
...
<Checkbox x:Name="cb"/>
...
</Expander>
</UserControl>
(code-behind)
public class MyCheckboxExpander : UserControl
{
MyCheckboxExpander()
{
InitializeComponent();
cb.Check += OnCheck;
}
void OnCheck(object sender, whatever2 args)
{
if (CheckboxTriggered != null)
CheckboxTriggered(new EventArgs<whatever>);
}
public event EventArgs<whatever> CheckboxTriggered;
}
WPF is so powerfull framework, that you can solve you problem just using next style for Expander:
<Style x:Key="myExpanderStyle" TargetType="{x:Type Expander}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<StackPanel>
<CheckBox x:Name="PART_CheckBox" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
<ComboBox x:Name="PART_ComboBox" ItemsSource="{TemplateBinding Content}" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="PART_ComboBox" Property="SelectedIndex" Value="0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
SAMPLE:
<Expander Style="{StaticResource myExpanderStyle}">
<x:Array Type="sys:String">
<sys:String>1</sys:String>
<sys:String>2</sys:String>
<sys:String>3</sys:String>
</x:Array>
</Expander>
Just XAML! I like XAML declarativity.
But from MVVM perspective, this approach has one disadvantage - I can't cover this case with unit tests. So, I would prefer:
create view model with properties: IsChecked(bound to CheckBox),
SelectedItem(bound to ComboBox) and Source(ItemsSource for ComboBox) -
abstration of my real view without any references on controls;
write a logic in view model that set or unset SelectedItem depending
on IsChecked property;
cover that logic with unit test (yep, you can
even start with this point, if you like test first approach).
I followed the suggestion provided by #Baboon and I created a custom control with a routed event named CheckedChanged, this way I can access it through the view's xaml and code-behind:
[TemplatePart(Name = "PART_Expander", Type = typeof(Expander))]
[TemplatePart(Name = "PART_CheckBox", Type = typeof(CheckBox))]
public class MyCustomExpander : Expander
{
static MyCustomExpander()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomExpander), new FrameworkPropertyMetadata(typeof(MyCustomExpander)));
}
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(MyCustomExpander),
new UIPropertyMetadata(false));
#region Events
private CheckBox chkExpander = new CheckBox();
public CheckBox ChkExpander { get { return chkExpander; } private set { chkExpander = value; } }
public static readonly RoutedEvent CheckedChangedEvent = EventManager.RegisterRoutedEvent("ExtraButtonClick",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(MyCustomExpander));
public event RoutedEventHandler CheckedChanged
{
add { AddHandler(CheckedChangedEvent, value); }
remove { RemoveHandler(CheckedChangedEvent, value); }
}
void OnCheckedChanged(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(CheckedChangedEvent, this));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
CheckBox chk = base.GetTemplateChild("PART_CheckBox") as CheckBox;
if (chk != null)
{
chk.Checked += new RoutedEventHandler(OnCheckedChanged);
chk.Unchecked += new RoutedEventHandler(OnCheckedChanged);
}
}
#endregion
}
I want to thank to #Baboon and #Vlad for their help.
I have a WPF application with several windows. I would like to define GLOBAL inputBindings.
To define LOCAL inputbindings, i just declare the input in Window.InputBindings or UserControl.InputBindings.
To define GLOBALs, I wish i could do the same with the Application class...
<Application
....>
<Application.InputBindings>
...
</Application.InputBindings>
If i have the same binding in 2 different windows, i have to code it twice. This doesn't meet D.R.Y.'s philosophy and i guess there is a better way...
EDIT : in his answer Kent Boogaart advices me to use Style. Unfortunately, i can't figure out how to define it. This is the code :
<Application.Resources>
<Style TargetType="Window">
<Setter Property="InputBindings">
<Setter.Value>
<Window.InputBindings>
<KeyBinding KeyGesture="Ctrl+M" Command="local:App.MsgCommand />
</Window.InputBindings>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
It raises an error : error MC3080: The Property Setter 'InputBindings' cannot be set because it does not have an accessible set accessor.
Is my style wrong?
Is there another solution?
Any ideas? thanks!
One solution is to use an Attached Property with a Style to set the InputBindings on all the controls of a given type in your application. Unfortunately, since you can't make a "catch-all" Style (that I know of, anyway), you'll have to create a Style for each control type on which you want to set the InputBindings (this shouldn't, however, be too many controls). Below is some sample code that shows how to do this:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public class MyAttached
{
public static readonly DependencyProperty InputBindingsProperty =
DependencyProperty.RegisterAttached("InputBindings", typeof(InputBindingCollection), typeof(MyAttached),
new FrameworkPropertyMetadata(new InputBindingCollection(),
(sender, e) =>
{
var element = sender as UIElement;
if (element == null) return;
element.InputBindings.Clear();
element.InputBindings.AddRange((InputBindingCollection)e.NewValue);
}));
public static InputBindingCollection GetInputBindings(UIElement element)
{
return (InputBindingCollection)element.GetValue(InputBindingsProperty);
}
public static void SetInputBindings(UIElement element, InputBindingCollection inputBindings)
{
element.SetValue(InputBindingsProperty, inputBindings);
}
}
}
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:WpfApplication1"
StartupUri="Window1.xaml">
<Application.Resources>
<Style TargetType="TextBox">
<Setter Property="loc:MyAttached.InputBindings">
<Setter.Value>
<InputBindingCollection>
<KeyBinding Key="A" Modifiers="Ctrl" Command="loc:Window1.MyAction" />
</InputBindingCollection>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Button">
<Setter Property="loc:MyAttached.InputBindings">
<Setter.Value>
<InputBindingCollection>
<KeyBinding Key="A" Modifiers="Ctrl" Command="loc:Window1.MyAction" />
</InputBindingCollection>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
<CommandBinding Command="loc:Window1.MyAction" Executed="MyAction_Executed" />
</Window.CommandBindings>
<StackPanel>
<Button Content="Try Ctrl+A Here!" />
<TextBox Text="Try Ctrl+A Here!" />
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class Window1
{
public static readonly RoutedUICommand MyAction = new RoutedUICommand("MyAction", "MyAction", typeof(Window1));
public Window1() { InitializeComponent(); }
private void MyAction_Executed(object sender, ExecutedRoutedEventArgs e) { MessageBox.Show("MyAction!"); }
}
}
You could create a Style that is applied to all your Windows. That Style could set the InputBindings.