I need to create input binding for Window.
public class MainWindow : Window
{
public MainWindow()
{
SomeCommand = ??? () => OnAction();
}
public ICommand SomeCommand { get; private set; }
public void OnAction()
{
SomeControl.DoSomething();
}
}
<Window>
<Window.InputBindings>
<KeyBinding Command="{Binding SomeCommand}" Key="F5"></KeyBinding>
</Window.InputBindings>
</Window>
If I init SomeCommand with some CustomCommand : ICommand it doesn't fire. SomeCommand property getter is never called.
For your case best way used MVVM pattern
XAML:
<Window>
<Window.InputBindings>
<KeyBinding Command="{Binding SomeCommand}" Key="F5"/>
</Window.InputBindings>
</Window>
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
In your view-model:
public class MyViewModel
{
private ICommand someCommand;
public ICommand SomeCommand
{
get
{
return someCommand
?? (someCommand = new ActionCommand(() =>
{
MessageBox.Show("SomeCommand");
}));
}
}
}
Then you'll need an implementation of ICommand.
This simple helpful class.
public class ActionCommand : ICommand
{
private readonly Action _action;
public ActionCommand(Action action)
{
_action = action;
}
public void Execute(object parameter)
{
_action();
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
For modifiers (key combinations):
<KeyBinding Command="{Binding SaveCommand}" Modifiers="Control" Key="S"/>
It might be too late but here is the simplest and shortest solution.
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.S)
{
// Call your method here
}
}
<Window x:Class="Test.MainWindow" KeyDown="Window_KeyDown" >
You will have to create your own Command implementing ICommand interface and initialize SomeCommand with the instance of that Command.
Now you have to set the DataContext of Window to self in order to make the Command Binding work:
public MainWindow()
{
InitializeComponents();
DataContext = this;
SomeCommand = MyCommand() => OnAction();
}
OR you will have to update your Binding as
<Window>
<Window.InputBindings>
<KeyBinding Command="{Binding SomeCommand, RelativeSource={RelativeSource Self}}" Key="F5"></KeyBinding>
</Window.InputBindings>
</Window>
This is how I solved this problem in my project:
<Window x:Class="MyNamespace.MyView"
(...)
xmlns:local="clr-namespace:MyNameSpace"
(...)
<Grid>
<Grid.InputBindings>
<KeyBinding Key="R" Command="{Binding ReportCommand,
RelativeSource={RelativeSource AncestorType=local:MyView}}" />
(...)
ReportCommand is an ICommand in MyView, not in the ViewModel.
Related
I'm trying to call a function in the viewmodel on startup the MVVM way. I thought I had it correct, but the code is never hitting the function call.
Here's my xaml:
<Window x:Class="TestWin.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:l="clr-namespace:Timeserver"
xmlns:viewmodel="clr-namespace:Timeserver.ViewModels"
Title="MainWindow"
Width="893"
Height="Auto"
Background="LightGray"
ResizeMode="NoResize"
SizeToContent="Height">
<Window.DataContext>
<viewmodel:MainWindowViewModel />
</Window.DataContext>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadData}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Here's my viewmodel (the necessary parts):
namespace TestWin.ViewModels
{
class MainWindowViewModel
{
private StructsModel model; // my model class
private ICommand loadDataCmd;
private ICommand showTimeWindowCmd;
private ICommand toggleExecuteCommand { get; set; }
private bool canExecute = true;
public bool CanExecute
{
get
{
return this.canExecute;
}
set
{
if (this.canExecute == value)
{
return;
}
this.canExecute = value;
}
}
public ICommand ToggleExecuteCommand
{
get
{
return toggleExecuteCommand;
}
set
{
toggleExecuteCommand = value;
}
}
public ICommand ShowTimeWindowCmd
{
//code here
}
public ICommand LoadDataCmd
{
get
{
return loadDataCmd;
}
set
{
loadDataCmd = value;
}
}
public void LoadData(object parameter)
{
model.GetData();
}
public MainWindowViewModel()
{
this.model = new StructsModel();
LoadDataCmd = new RelayCommand(LoadData, param => this.canExecute);
ShowTimeWindowCmd = new RelayCommand(ShowTimeWindow, param => this.canExecute);
toggleExecuteCommand = new RelayCommand(ChangeCanExecute);
}
public void ShowTimeWindow(object parameter)
{
//code here
}
public void ChangeCanExecute(object obj)
{
canExecute = !canExecute;
}
}
}
The function in question that is not being hit is LoadData(). It calls GetData() in my model class, which I cannot show for reasons. Not sure what else to try. I've seen other questions on SO doing the same thing I'm doing. My other function ShowTimeWindow is set up the exact same way and does get hit.
If you really want the call to be made at Loaded, you could remove the xaml code
<Window.DataContext>
<viewmodel:MainWindowViewModel />
</Window.DataContext>
and bind the viewmode from code behind, like Mat said above. Then, the Command you have bound will be triggered (if it has the same name as the one in the viewmodel), and you will not need to call the vm.LoadData() in the constructor.
Also, if the command is not used for anything else than to load data at "Loaded", CanExecute is useless.
You can create your ViewModel in code behind. Than you can call the methods you need. If you want to go for excellence you can use a Factory pattern or a dependency injection container (e.g. Windsor)
public MainWindow()
{
InitializeComponent();
MainWindowViewModel vm = new MainWindowViewModel();
DataContext = vm;
vm.LoadData();
}
I'm developing my first application in WPF with the pattern MVC and I have a question.
I have created a usercontrol from type Grid to made a custom title bar. This grid contains a X button and I want to associate this button to a command.
My grid in XAML:
<Grid x:Class="Views.TitleBarView"
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"
mc:Ignorable="d"
Style="{DynamicResource TitleStyleGrid}"
x:Name="barView">
<Label x:Name="labelAppName" Style="{DynamicResource TitleStyleLabel}" Content="Title"/>
<Button x:Name="bttnClose" Style="{DynamicResource ButtonStyleCloseWindow}" Command="{Binding CloseCommand}"/>
<Button x:Name="buttonMinimize" Style="{DynamicResource ButtonStyleMinimizeWindow}" Command="{Binding MinimizeCommand}"/>
</Grid>
The C# view:
public partial class TitleBarView : Grid
{
public TitleBarView()
{
InitializeComponent();
TitleBarViewModel tvm = new TitleBarViewModel();
tvm.RequestClose += (s, e) => this.Close();
tvm.RequestMinimize+= (s, e) => this.Minimize();
DataContext = tvm;
}
private void Close()
{
Window.GetWindow(this).Close();
}
private void Minimize()
{
Application.Current.MainWindow.WindowState = System.Windows.WindowState.Minimized;
}
}
The C# viewModel:
public class TitleBarViewModel : ViewModelBase, IRequestMinimizeViewModel, IRequestCloseViewModel
{
private RelayCommand minimizeCommand;
protected RelayCommand closeCommand;
public event EventHandler RequestMinimize;
public event EventHandler RequestClose;
#region MinimizeCommand
public ICommand MinimizeCommand
{
get
{
if (minimizeCommand == null)
{
minimizeCommand = new RelayCommand(Minimize);
}
return minimizeCommand;
}
}
private void Minimize()
{
RequestMinimize(this, null);
}
#endregion
#region CloseCommand
public ICommand CloseCommand
{
get
{
if (closeCommand == null)
{
closeCommand = new RelayCommand(Close);
}
return closeCommand;
}
}
protected void Close()
{
RequestClose(this, null);
}
#endregion
}
I saw that it's not recommended to set a DataContext on a userControl. And when I do this, I can't change the close command. For example I want that when the main windows calls command close it calls Application.Current.Shutdown(); instead of Application.Current.Shutdown();
I know that I have something wrong but I'm too confuse to solve it. Can you explain me how to create command for userControl ? (Or just tell me what I'm doing wrong)
Thank you
i'm new in WPF and MVVM. I read many articles about WPF commands, but i have still problem with sending value from property text of textbox to ViewModel.
I'm using entity framework code first.
I want to show text from textbox in MessageBox, but when I click to button with command, linked property of viewmodel is null.
Please can you help me?
View- DetailIncidentWindow.xaml
xmlns:wm="clr-namespace:Admin.ViewModels"
<StackPanel>
<StackPanel.DataContext>
<wm:CommentViewModel/>
</StackPanel.DataContext>
<TextBlock Text="Text komentáře:" Style="{StaticResource TextBlockLabel}" Margin="0,10,0,0"/>
<TextBox Name="TextBox_textKomentar" Width="auto" Height="100" TextWrapping="Wrap" Text="{Binding TextKomentar, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding TextKomentar, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
Ribbon button- DetailIncidentWindow.xaml
<Custom:RibbonGroup.DataContext>
<wm:CommentViewModel/>
</Custom:RibbonGroup.DataContext>
<Custom:RibbonButton
LargeImageSource="..\Shared\img\save_diskete.png"
Label="Show text"
Command="{Binding ButtonCommand}">
</Custom:RibbonButton>
ViewModel- KomentarViewModel.cs
namespace Admin.ViewModels
{
class CommentViewModel:BaseViewModel
{
#region Data
private string textKomentar;
public string TextKomentar
{
get
{
return textKomentar;
}
set
{
textKomentar = value;
OnPropertyChanged("TextKomentar");
}
}
private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
OnPropertyChanged("ButtonCommand");
}
}
#endregion
#region Constructor
public CommentViewModel()
{
ButtonCommand = new RelayCommand(new Action<object>(ShowMessage));
}
#endregion
#region Methods
public void ShowMessage(object obj)
{
MessageBox.Show(TextKomentar);
}
#endregion
}
}
Command- RelayCommand.cs
class RelayCommand : ICommand
{
private Action<object> _action;
public RelayCommand(Action<object> action)
{
_action = action;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
if (parameter != null)
{
_action(parameter);
}
else
{
_action("Hello World");
}
}
#endregion
}
You should not create multiple instances of your view model, like you do in
<StackPanel.DataContext>
<wm:CommentViewModel/>
</StackPanel.DataContext>
and
<Custom:RibbonGroup.DataContext>
<wm:CommentViewModel/>
</Custom:RibbonGroup.DataContext>
The value of the DataContext property is inherited by child elements, so you could just set it at the top level, e.g. the Window:
<Window ...>
<Window.DataContext>
<wm:CommentViewModel/>
</Window.DataContext>
...
</Window>
I've got some XAML like the following:
<UserControl x:Class="Foo">
<UserControl.Resources>
<ContextMenu x:Key="ContextMenu1">
<MenuItem Header="Command 1a"/>
<MenuItem Header="Command 1b"/>
</ContextMenu>
<ContextMenu x:Key="ContextMenu2">
<MenuItem Header="Command 2a"/>
<MenuItem Header="Command 2b"/>
</ContextMenu>
</UserControl.Resources>
<DockPanel>
<TreeView>
<TreeView.Resources>
<DataTemplate DataType="{x:Type Type1}">
<StackPanel ContextMenu="{StaticResource ContextMenu1"}/>
</DataTemplate>
<DataTemplate DataType="{x:Type Type2}">
<StackPanel ContextMenu="{StaticResource ContextMenu2"}/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</DockPanel>
</UserControl>
and a code behind similar to the following:
public class Type1 {
public void OnCommand1a() {}
public void OnCommand1b() {}
}
public class Type2 {
public void OnCommand2a() {}
public void OnCommand2b() {}
}
What do I need to do so that clicking the respective items on the menus calls the corresponding function?
If I add:
Command="{Binding Path=OnCommand1a}" CommandTarget="{Binding Path=PlacementTarget}"
etc then at runtime I get errors about how OnCommand1a is not a property. Some searching suggests this has something to do with a RoutedUIEvent, but I don't really understand what that's about.
If I use
Click="OnCommand1a"
then it looks for OnCommand1a() on the UserControl instead of on the type that is bound to the DataTemplate.
What is the standard way of dealing this?
First of all you need a class that extends ICommand.
You can use this:
public class DelegateCommand : ICommand
{
private readonly Action<object> executeMethod = null;
private readonly Func<object, bool> canExecuteMethod = null;
public event EventHandler CanExecuteChanged
{
add { return; }
remove { return; }
}
public DelegateCommand(Action<object> executeMethod, Func<object, bool> canExecuteMethod)
{
this.executeMethod = executeMethod;
this.canExecuteMethod = canExecuteMethod;
}
public bool CanExecute(object parameter)
{
if (canExecuteMethod == null) return true;
return this.canExecuteMethod(parameter);
}
public void Execute(object parameter)
{
if (executeMethod == null) return;
this.executeMethod(parameter);
}
}
Then, in your class Type1 you have to declare this:
public DelegateCommand OnCommand1a {get; private set;}
and set it in your Type1 constructor in this way:
OnCommand1a = new DelegateCommand(c => Cmd1a(), null);
where Cmd1a is:
private void Cmd1a()
{
//your code here
}
Finally, in your xaml:
Command="{Binding Path=OnCommand1a}"
I have using a DelegateCommand and i want to pass the UserControl with Command.
#region OpenViewCommand
private DelegateCommand<UserControl> _openViewCommand;
public ICommand OpenViewCommand
{
get
{
if (_openViewCommand == null)
_openViewCommand = new DelegateCommand<UserControl>(new Action<UserControl>(OpenView));
return _openViewCommand;
}
}
public void OpenView(UserControl ViewName)
{
UserControl ctrl = (UserControl)ViewName;
JIMS.Controls.Message.Show(ViewName.ToString());
}
#endregion
Command in XAML
<Button Name="btnStockGroups" Command="{Binding OpenViewCommand}" CommandParameter="JIMS.View.Stock.StockGroups">stock group</Button>
If you give your UserControl an x:Name (e.g. "MyView"), you should be able to do something like this:
<Button Name="btnStockGroups"
Command="{Binding OpenViewCommand}"
CommandParameter="{Binding ElementName=MyView}">