I want to have a window level KeyBinding with command paramter as window itself.
e.g.
<KeyBinding Command="{Binding CloseCommand}" CommandParameter="{Binding ElementName=mainWindow}" Key="Esc"/>
Binding works, but paramter comes in as null. What's the work around?
Following is my Command:`
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("Action excute is null");
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Actually this working for me - but i am using the RelayCommand<FrameworkElement> of [MVVM Light Toolkit1.
<Window.InputBindings>
<KeyBinding Command="{Binding MyCommand, ElementName=MainRoot}" CommandParameter="{Binding ElementName=MainRoot}" Key="Esc"/>
</Window.InputBindings>
In my case the Command comes from a DependencyProperty, but that shouldn't make a big difference.
public RelayCommand<FrameworkElement> MyCommand
{
get { return (RelayCommand<FrameworkElement>)GetValue(MyCommandProperty); }
set { SetValue(MyCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for MyCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyCommandProperty =
DependencyProperty.Register("MyCommand", typeof(RelayCommand<FrameworkElement>), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
InitializeComponent();
MyCommand = new RelayCommand<FrameworkElement>(DoSthYo);
}
public void DoSthYo(FrameworkElement fwE)
{
var x = fwE;
}
So because this is working - i think its your Command that does not support CommandParameter maybe.
My advice is to use a RelativeSource in your CommandParameter binding:
<Window.InputBindings>
<KeyBinding Command="{x:Static local:CloseWindowCommand.Instance}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Key="Esc" />
</Window.InputBindings>
In this way your binding can be independant from the name of your Window.
Then you can create a static command for closing each window of your application:
public class CloseWindowCommand : ICommand
{
public static readonly ICommand instance = new CloseWindowCommand();
public event EventHandler CanExecuteChanged;
private CloseWindowCommand()
{
}
public bool CanExecute(object parameter)
{
return (parameter is Window);
}
public void Execute(object parameter)
{
Window win;
if (CanExecute(parameter))
{
win = (Window)parameter;
win.Close();
}
}
}
I hope it can help you.
Related
So I have this View:
<StackPanel>
<TextBox x:Name="Name"/>
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
And I have this ViewModel:
internal class ShellViewModel : PropertyChangedBase
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
NotifyOfPropertyChange(() => Name);
NotifyOfPropertyChange(() => CanSayHello());
}
}
public bool CanSayHello()
{
bool isenabled = !string.IsNullOrWhiteSpace(Name);
return isenabled;
}
public void SayHello()
{
MessageBox.Show(string.Format("Hello, {0}!", Name));
}
}
But whenever I enter some value in the textbox, I got this exception:
{"Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'."}
In the commercial app that I'm developing I must have the CanSayHello() member in the VM as a method, not as a property. What should I do?
You have that exception because you are calling NotifyOfPropertyChange on CanSayHello and CanSayHello is a method, not a property.
Change to:
public bool CanSayHello
{
get { return !string.IsNullOrWhiteSpace(Name); }
}
You should use commands to bind actions to UI items. There is an implementation of ICommand called RelayCommand which is typically used in most WPF projects. It allows you to use method, property or predicate.
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
I have two radio button.I just want to capture the selected radio button value in viewmodel.I have defined a method GetLOB() in which I want to capture the commandParameter value.
Here is my code
<RadioButton GroupName="Os" Content="Payroll" IsChecked="{Binding ObjEntrySheetManagerViewModel.CheckedProperty}" Command="LobType" CommandParameter="Payroll" Grid.Row="4" Grid.Column="0" Margin="25,15,0,0"/>
<RadioButton GroupName="Os" Content="Sales" Grid.Row="4" Grid.Column="1" Command="LobType" CommandParameter="Payroll" Margin="5,15,0,0"/>
private RelayCommand _LobType;
public ICommand LobType
{
get
{
if (_LobType == default(RelayCommand))
{
_LobType = new RelayCommand(GetLOB);
}
return _LobType;
}
}
private void GetLOB()
{
}
Capture parameter using lambda (assuming RelayCommand used by you have overloaded constructor which will take Action<object> as argument)
public ICommand LobType
{
get
{
if (_LobType == default(RelayCommand))
{
_LobType = new RelayCommand(param => GetLOB(param));
}
return _LobType;
}
}
private void GetLOB(object parameter)
{
}
Relay command sample from MSDN (in case you need):
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{ }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion
}
I'm looking for an example how to replace this old code for RibbonApplicationMenuItem. Question is how to replace removed RibbonCommand
<ResourceDictionary>
<r:RibbonCommand
x:Key="MenuItem1"
CanExecute="RibbonCommand_CanExecute"
LabelTitle="Menu Item 1"
LabelDescription="This is a sample menu item"
ToolTipTitle="Menu Item 1"
ToolTipDescription="This is a sample menu item"
SmallImageSource="Images\files.png"
LargeImageSource="Images\files.png" />
</ResourceDictionary>
</r:RibbonWindow.Resources>
<r:RibbonApplicationMenuItem Command="{StaticResource MenuItem1}">
</r:RibbonApplicationMenuItem>
You can use RelayCommand.
Binding in this case is very simple:
<ribbon:RibbonApplicationMenuItem Header="Hello _Ribbon"
x:Name="MenuItem1"
ImageSource="Images\LargeIcon.png"
Command="{Binding MyCommand}"
/>
Your ViewModel class in this case, must contain property MyCommand of ICommand type:
public class MainViewModel
{
RelayCommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
{
_myCommand = new RelayCommand(p => this.DoMyCommand(p),
p => this.CanDoMyCommand(p));
}
return _myCommand;
}
}
private bool CanDoMyCommand(object p)
{
return true;
}
private object DoMyCommand(object p)
{
MessageBox.Show("MyCommand...");
return null;
}
}
Don't forget assign DataContext of MainWindow:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
RelayCommand class:
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
I have 8 HyperlinkButton on my silverlight application.
I want to call method HyperlinkButtonClick_Event when each of them will be clicked.
Can i do it on style ?
If 'no' so how can i do it without adding the method explicitly on each of the HyperlinkButton instance ?
How about using something like this in your style:
<Setter Property="Command" Value="{Binding ClickCommand}" />
And using a Command, such as a DelegateCommand, with an Execute action replacing your HyperlinkButtonClick_Event code.
This is also obviously going to require you to have the datacontext set correctly for each of your buttons...
The DelegateCommand in it's VERY simplest form:
public class DelegateCommand : ICommand
{
private Func<object, bool> canExecute;
private Action<object> executeAction;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
this.executeAction = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
this.executeAction(parameter);
}
public bool CanExecute(object parameter)
{
return this.canExecute(parameter);
}
}
You can find implementations of this everywhere, from SO to MSDN...
public class MyCheckBox : CheckBox
{
public MyCheckBox()
{
this.Click += new RoutedEventHandler(MyCheckBox_Click);
}
void MyCheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox chk = (sender as CheckBox);
}
}
<foo:mycheckbox ................/>
Define your own class and use the foo:mycheckbox in style file.
I am using MVVM pattern. I have a
Text box whose Text property is bound to ViewModel's(VM supports INotifyProperyChange) Text property
Button whose command is bound to VM's ICommand property type
You may think of this as a SearchTextBox and SearchButton
The problem I am facing is that when I enter the text in SearchTextBox and click on SearchButton then only the SearchTextBox bound set property implementation is called but the Command for SearchButton click never executes (Note: ICommand CanExecute handler always returns True)
It works fine if I either tab out of SearchTextBox using TAB key or use mouse to move focus away from SearchTextBox and then click the SearchButton. That means do two seperate actions to trigger both the events seperately. Ideally clicking on the SearchButton should result in the SearchTextBox loose focus thus calling Set property and the click on the Search button translates into the command execution.
Code is as below
XAML:
<TextBox Text="{Binding Path=SearchText,Mode=TwoWay}"/>
<Button Content="Search" Width="100" Command="{Binding MySearchCommand}"/>
C#:
public String _SearchText;
public String SearchText
{
get { return _SearchText; }
set
{
_SearchText = value;
OnPropertyChanged("SearchText");
}
}
ICommand implementation is a standard implemenetation with no fancy code and CanExecute handler always returns True
Try to isolate the issue by writing a small test project that reproduces the issue, if you can repro then please post the code. Usually when you repro the issue outside of your main project the problem and the solution become obvious.
I created a sample application to reproduce this problem.
I placed breakpoint and added a Debug.Writeline in SearchText - Set property and MySearchCommandExecute method.
When breakpoints are set, only the SearchText - Set property gets called. I observed that if I remove the breakpoint from SearchText - Set property then both the property and the command are correctly executed. Looks like some problem with VS 2008 but I may be wrong.
The relevant sample code is as below
class SearchViewModel : ViewModelBase
{
public SearchViewModel()
{
}
public String _SearchText;
public String SearchText
{
get { return _SearchText; }
set
{
System.Diagnostics.Debug.WriteLine("Set Membership called");
OnPropertyChanged("SearchText");
}
}
#region Commands
RelayCommand _SearchCommand;
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = new RelayCommand(param => this.MySearchCommandExecute(), param => this.MySearchCommandCanExecute);
}
return _SearchCommand;
}
}
public void MySearchCommandExecute()
{
System.Diagnostics.Debug.WriteLine("MySearchCommandExecute called");
// Do Search
}
public bool MySearchCommandCanExecute
{
get
{
return true;
}
}
#endregion
}
SearchView.xaml
<UserControl x:Class="WpfApplication2.SearchView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="4">
<Label Foreground="Black" FontFamily="Calibri" Width="155" Margin="4,0,4,0" Content="SearchText"/>
<TextBox Foreground="Black" FontFamily="Calibri" Width="155" Margin="4,0,4,0" Text="{Binding Path=SearchText}"/>
</StackPanel>
<Button HorizontalAlignment="Left" Content="Search" Width="100" Command="{Binding SearchCommand}" Margin="8"/>
</StackPanel>
</UserControl>
RelayCommand.cs
// Reference: MSDN sample
class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("relaycommand execute");
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
Byte,
Sorry for my late response, but I hope it will become handy anyway. I'm very busy lately so I couldn't debug your code (I'll try to do that when I have more time), but please try my sample code pasted below (It works perfectly for me). As you can see it's extremely simple. I used your xaml, but for Window:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new TempViewModel();
}
}
public class TempViewModel : INotifyPropertyChanged
{
private String _searchText;
private ICommand _searchCommand;
#region Commands
protected class Search : ICommand
{
private TempViewModel _viewModel;
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
public void Execute(object parameter)
{
//MessageBox in VM is just for demonstration
MessageBox.Show("command executed with search string: " + this._viewModel._searchText);
}
public Search(TempViewModel viewModel)
{
this._viewModel = viewModel;
}
}
#endregion //Commands
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion //INotifyPropertyChanged
#region Public properties
public String SearchText
{
get
{
return this._searchText;
}
set
{
this._searchText = value;
OnPropertyChanged("SearchText");
}
}
public ICommand SearchCommand
{
get
{
return this._searchCommand;
}
set
{
this._searchCommand = value;
OnPropertyChanged("SearchCommand");
}
}
#endregion //Public properties
public TempViewModel()
{
this.SearchCommand = new Search(this);
this.SearchText = "Sample string";
}
}
Please feel free to ask if you have any further questions.
EDIT: Ah, sorry, but I changed Command="{Binding SearchCommand}" to Command="{Binding Path=SearchCommand}"