I have one textbox and one button. The Button Command should change the property which is binded to the TextBox.
But I don't see any visual changes after command execution.
I think it easy question related to wpf binding
Please help me with this issue
Source of app:
<UserControl.DataContext>
<local:SampleViewModel />
</UserControl.DataContext>
<Grid>
<StackPanel>
<TextBox Height="23" Width="120" Text="{Binding MyName}" />
<Button Content="Click" Command="{Binding ButtonCommand}" />
</StackPanel>
</Grid>
ViewModel:
Private _myName As String
Public Property MyName As String
Get
Return _myName
End Get
Set(value As String)
_myName = value
OnPropertyChanged("MyName")
End Set
End Property
Public _buttonCommand As DelegateCommand
Public ReadOnly Property ButtonCommand As DelegateCommand
Get
Return If(_buttonCommand IsNot Nothing, _buttonCommand,
New DelegateCommand(AddressOf Execute, AddressOf CanExecute))
End Get
End Property
Private Sub Execute()
MyName = "Executed"
End Sub
Private Function CanExecute() As Boolean
Return True
End Function
Public Event PropertyChanged As PropertyChangedEventHandler
Private Sub OnPropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Do the following:
1.
Class MainWindow
Implements INotifyPropertyChanged
2 . In Public Sub New() make sure you write Me.DataContext = Me to set the DataContext
Note: Ignore step 2 if you're using a ViewModel and setting it in XAML
3 . Modify the ProperyChanged like this:
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Only after implementing INotifyPropertyChanged correctly will the Binding correctly refresh the MyName property after the PropertyChanged event
Here is a code that works with your exact XAML (I took the DelegateCommand implementation from http://wpftutorial.net/DelegateCommand.html ) Sorry it's C#, i'm really not into VB :D
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public virtual bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public virtual void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
public class SampleViewModel : INotifyPropertyChanged
{
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public DelegateCommand _buttonCommand;
public DelegateCommand ButtonCommand
{
get
{
if (_buttonCommand == null)
{
_buttonCommand = new DelegateCommand(Execute);
}
return _buttonCommand;
}
}
public void Execute(object o)
{
MyName = "executed";
}
public string MyName { get { return _myName; } set { _myName = value; OnPropertyChanged("MyName"); } }
private string _myName;
}
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);
}
}
Problem: Buttons never gets enabled.
<Button Name="btnCompareAxises"Command="{Binding CompareCommand}"
Content="{Binding VM.CompareAxisButtonLabel}"
IsEnabled="{Binding VM.IsCompareButtonEnabled}">
</Button>
ViewModel constructor:
this.CompareCommand = new DelegateCommand(CompareCommand, ValidateCompareCommand);
The problem seems to be related to the CanExecute eventhandler of the registered Command of the button.
The CanExecute handler returns false when the application loads.
This is fine, as the conditions are not met initially.
The canExecute handler only runs on application startup or when the button is clicked. You cannot click a disabled button, so the button stays disabled forever if the initial value returned form the CanExecute handler is false!
Question:
Do I have to enable the button again, only using the command bound to it.
Something like, hey command please reevaluate if the conditions for this buttons are met ?
Why sits the IsEnabled property under section Coercion and not under local?
The command:
public class DelegateCommand : ICommand
{
private readonly Func<object, bool> canExecute;
private readonly Action<object> execute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void RaiseCanExecuteChanged()
{
this.OnCanExecuteChanged();
}
protected virtual void OnCanExecuteChanged()
{
var handler = this.CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Solved:
I had to adapt the DelegateCommand class to make it work:
I have added CommandManager.RequerySuggested to the public CanExecuteChanged Event property.
Now it will automatically re-evaluate the CanExecute method of the command when soemthing changes in the UI!
public class DelegateCommand : ICommand
{
private readonly Func<object, bool> canExecute;
private readonly Action<object> execute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
/// CommandManager
/// Go to the "References" part of your class library and select "Add Reference".
/// Look for an assembly called "PresentationCore" and add it.
public event EventHandler CanExecuteChanged
{
add
{
_internalCanExecuteChanged += value;
CommandManager.RequerySuggested += value;
}
remove
{
_internalCanExecuteChanged -= value;
CommandManager.RequerySuggested -= value;
}
}
event EventHandler _internalCanExecuteChanged;
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void RaiseCanExecuteChanged()
{
this.OnCanExecuteChanged();
}
protected virtual void OnCanExecuteChanged()
{
var handler = this._internalCanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Removed this from the button:
IsEnabled="{Binding VM.IsCompareButtonEnabled}"
The binding here is not necessary, as the CanExecute handler will take care of the enabled/disabled state of the button!
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 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}"