WPF Button binding to ICommand not firing - wpf

I have a Button bound to an ICommand interface but it isn't being fired when I run the application.
The button should be disabled when the app runs, putting a breakpoint in the ICommand or CanUpdate but it isn't being hit.
The ICommand seems to have been implemented correctly as far I can see - have substituted value in CanUpdate for simplicity...
Scratching my head to workout what is missing?....
XAML
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="1">
<RadioButton Width="64" IsChecked="{Binding Passed}" GroupName="T1">Yes</RadioButton>
<RadioButton Width="64" IsChecked="{Binding Passed, Converter={StaticResource InverseBoolRadioConverter}}" GroupName="T1" >No</RadioButton>
</StackPanel >
Button Command="{Binding UpdateHasPassed}" Content="Update"></Button>
Code-Behind:-
private RelayCommand hasPassed;
public bool Passed
{
get
{
return passed;
}
set
{
if (passed !=value )
{
passed = value;
OnPropertyChanged();
}
}
}
public ICommand HasPassed
{
get
{
if (hasPassed == null)
{
haspassed = new RelayCommand( param => CanUpdate());
}
return haspassed;
}
}
private bool CanUpdate()
{
return (1 != 2)
}

You're on the right track looking into INotifyPropertyChanged. I would also recommend reading up on WPF data bindings, the ICommand interface (and specifically creating a RelayCommand, more on that later), and MVVM design.
The benefit of WPF data bindings and ICommand is that you can control when the button gets enabled or disabled, based on your conditional criteria (i.e. name has changed from its original value). With the tips mentioned here, you should be able to do what you want in short time. Just google each of the topics and you'll get what you need.

Related

Changing the background color of a textblock in MVVM-WPF (and retaining it)

Here is the working code i have: The text and background color property do change when I click the button (but for a micro second) and are then set back to the default text/color. Seems like RaisePropertyChanged is being triggered again and again. Can somebody help point what I am doing wrong?
MainWindow.xaml code
<Window x:Class="BuiltIn_Custom_Commands_Eg.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="{Binding txtblck_text, StringFormat=Default: {0}}" Padding="10" FontStyle="Italic" Background="{Binding txtblck_color}"/>
<Button Content="Change Color" Width="100" Height="30" Margin="20" Command="{Binding OkCommand}" />
</StackPanel>
</Grid>
ViewModel Code:
class Example_ViewModel : ViewModelBase
{
#region Properties
private string _txtblck_text;
private Brush _txtblck_color;
public ICommand OkCommand {get; set;}
public string txtblck_text
{
get { return _txtblck_text; }
set
{
_txtblck_text = value;
RaisePropertyChanged("txtblck_text");
}
}
public Brush txtblck_color
{
get { return _txtblck_color; }
set
{
_txtblck_color = value;
RaisePropertyChanged("txtblck_color");
}
}
#endregion
#region Constructor
public Example_ViewModel()
{
OkCommand = new myCommand(myOkExecute, myCanOkExecute);
}
#endregion
private void myOkExecute(object parameter)
{
txtblck_color = Brushes.CadetBlue;
//RaisePropertyChanged("txtblck_color");
txtblck_text = "You Clicked me!!!";
//RaisePropertyChanged("txtblck_text");
}
private bool myCanOkExecute(object parameter)
{
txtblck_color = Brushes.Yellow;
txtblck_text = "You havent clicked me!!!";
return true;
}
}
The CanExecute method will and should be called whenever bindings change. Therefore changing a binding in the Execute method (color) will cause CanExecute to be called again.
Instead, why dont you initialize the colors private member once in the constructor as follows.
public Example_ViewModel()
{
OkCommand = new myCommand(myOkExecute, myCanOkExecute);
_txtblck_color = = Brushes.Yellow;
}
Note, the same is also true for the text property. Normally all property private member should be set up with defaults on initialize (constructor) as this avoids unnecessary calls to INotifyPropertyChanged.
Also, in order to test how the code is behaving and to confirm this just set some breakpoints in the CanExecute method to see how the program flow is behaving.
Your problem is that you shouldn't do any setting of your properties in your myCanOkExecute...because it is that that is being called and changing your properties back to the yellow, etc.
The CanExecute methods of Commands could be called multiple times and sometimes when you don't expect ...e.g. when the focus changes to a different control, when certain controls are being edited/sent keypress, after a Command has been executed, when someone calls CommandManager.InvalidateRequerySuggested, etc.
Thus what's happening is your myCanOkExecute is being called shortly after you have clicked and executed your button.

UI not updating even when CollectionChanged or PropertyChanged events are fired

Background, from MSDN:
ObservableCollections CollectionChanged event will only be raised
when properties of ObservableCollection are changed (Addition,
deletion of an element) and not when the properties of existing elements are changed.
Bummer, because I need the UI to update when a specific property of an existing element changes. I tried firing both CollectionChanged events and PropertyChanged Events but neither worked.
My situation:
In my application, I have a listbox bound to an observablecollection where the visibility of the items depends on the "Favorite" property of each item using a BoolToVisibilityConverter. XAML:
<ListBox x:Name="FavoritesListBox"
Margin="0,0,-12,0"
ItemsSource="{Binding FeedItemOCollection}"
SelectionChanged="FavoritesListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Name="FavoritesStackPanel"
Margin="0,0,0,17" Visibility="{Binding Favorite, Converter={StaticResource BooltoVisibilityConverter}}">
<TextBlock Text="{Binding Title}"
TextWrapping="Wrap"
Margin="12,0,0,0"
Style="{StaticResource PhoneTextLargeStyle}" />
<TextBlock Text="{Binding PublishDate,Converter={StaticResource DateTimeToDateConverter}}"
TextWrapping="Wrap"
Margin="12,-6,12,0"
Style="{StaticResource PhoneTextSmallStyle}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note: This object is initialized in App.Xaml.cs and so is global for the whole application. This may be the unusual thing that is causing things not to work for me.
Once the initial binding occurs, changes to the value of an element's Favorite property does not cause the item to show up or disappear from the Favorites Listbox as is desired for the reason noted at the beginning of the post. This is expected.
To work around this I've tried firing both CollectionChanged events and PropertyChanged Events when the Favorite property is changed to get the UI to update, but neither worked and I'm confused why not. I have succeed in working around my issue, by adding and removing the element from the ObservableCollection, but clearly this is a hack. Code:
public void MarkFavorite(FeedItem feedItem)
{
try
{
feedItem.Favorite = true;
//CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); <-- why doesn't this work?
//PropertyChanged(this, new PropertyChangedEventArgs("Count")); <-- why doesn't this work?
this.Remove(feedItem); <-- this works, but is a hack
this.Add(feedItem); <-- this works, but is a hack
SaveToIso();
}
catch (Exception exception)
{
//TODO: Log this.
}
}
Why doesn't firing the events work?
Many thanks ahead of time.
Your FeedItem class must implement INotifyPropertyChanged interface, and your Favorite property must look like:
private bool _Favorite;
private bool _Favorite;
public bool Favorite
{
get { return _Favorite; }
set
{
_Favorite = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Favorite"));
}
}
Or you can extract a method
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
and your property will look like this:
private bool _Favorite;
public bool Favorite
{
get { return _Favorite; }
set
{
_Favorite = value;
OnPropertyChanged("Favorite");
}
}

Inner property of ItemsControl not updating when bound on ItemsSource

I have an ItemsControl like the following
<ItemsControl ItemsSource="{Binding MyClass.Links}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid d:DesignWidth="450" d:DesignHeight="245" Height="Auto" Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="145"/>
<ColumnDefinition Width="Auto" MinWidth="179"/>
</Grid.ColumnDefinitions>
<HyperlinkButton Content="{Binding ViewName}" IsEnabled="{Binding ViewEnabled, Mode=OneWay}" cmd:Click.Command="{Binding DataSource.ViewCommand, Source={StaticResource DataContextProxy}}" cmd:Click.CommandParameter="{Binding}" Margin="4"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
I have an ObservableCollection of the following class that the itemssource is getting bound to
public class LinkClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string ViewName { get; set; }
private bool _viewEnabled;
public bool ViewEnabled {
get { return this._viewEnabled; }
set
{
if (value != this._viewEnabled)
{
this._viewEnabled = value;
if (this.PropertyChanged != null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
this.PropertyChanged(this, new PropertyChangedEventArgs("ViewEnabled"))
);
}
}
}
}
}
When the command is hit in the view model, the bound link's ViewEnabled is getting set to false (disable link for view I'm looking at). The problem is, the link isn't actually getting disabled (IsEnabled set to false).
So the end question is, why isn't this working? I'm new to MVVM and silverlight, so I'm hoping it's something simple.
UPDATE
I'm setting the ViewEnabled property to true for all but the clicked button's bound LinkClass, which I'm setting to false. It is firing the PropertyChanged event for each (that changes), but not updating the UI. I ran an empty converter with the binding and it isn't getting hit either when the link is clicked, so the PropertyChanged isn't bubbling properly (or as I suspect it should anyway).
Here's the code setting the ViewEnabled properties of my collection of LinkClass:
public ICommand ViewCommand
{
get {
return new DelegateCommand<object>(param =>
{
this.ViewSelected((LinkClass)param);
});
}
}
public void ViewSelected(LinkClass link)
{
foreach (var containerLink in _myClass.Links)
{
if (containerLink == link)
containerLink.ViewEnabled = false;
else
containerLink.ViewEnabled = true;
}
...other code here
}
Well it might actually be getting disabled but if your ViewCommand isn't paying attention to that property then you're stuck. Especially since it looks like that command is an attached property.
Googling got me this post that you might want to look at.
But personally I would look at your CanExecute of your ViewCommand and make sure that it is only running if ViewEnabled == true
When I was using MVVM, in the setter of my properties I had a method named NotifyPropertyChanged() and would call it passing the string value for the property's name. I'm not sure what Deployment.Current.Dispatcher.BeginInvoke(...) does, but this method always worked for me.
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler.IsNotNull())
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
So in my property I would do something like...
public Nullable<int> UpdatedBy
{
get { return _updatedBy; }
set
{
if (_updatedBy.IsEqualTo(value))
return;
_updatedBy = value;
NotifyPropertyChanged("UpdatedBy");
}
}
Also, just grasping at straws, but try putting {Binding Path=ViewEnabled, ...}
Hope this helps.
Taking Jose's advice, I looked at the canExecute method of the ViewCommand (DelegateCommand) I was using, but implementing the method didn't solve the problem, as it only was run once, and not when changed. I found an example recommending to use the PropertyChanged event handler of the INotifyPropertyChanged class to call the RaiseCanExecuteChanged() method of the DelegateCommand. I did this for all of the LinkClass instances, as shown here for 1 before setting it to _myClass.Links:
var link = new LinkClass()
{
...
ViewEnabled = true
};
link.PropertyChanged += new PropertyChangedEventHandler(link_PropertyChanged);
return link;
I did this, but to no avail. I then found this blog post:DelegateCommand in Prism loses eventhandler and CanExecute never gets called I then switched from Prism to a RelayCommand class and it worked! Hopefully this helps someone else out.
UPDATE
The actual issue was in using Prism's cmd:Click.Command and cmd:Click.CommandParameter in xaml. Switching from that to Command and CommandParameter properties in xaml, as I did after switching to the RelayCommand, is what actually got it working.

Databinding IsEnabled of button in a xaml file

I want to bind a buttons IsEnabled property to a bool value that is retunred by a WCF web service.
Following is the details...
I have a datagrid in one of my xaml file. In this grid i have a button as part of DataGridTemplateColumn. now i want to data bind the isenable of this button to a bool value returned by the web service.
Can't we done something very simple like..
<Button x:Name="btnUpdRequest" Content="Update" Click="btnUpdRequest_Click" Margin="2" IsEnabled="{Binding isUpdateable}" />
where isUpdateable is one of the value returned by the web service.
Thanks..
What you're describing is very doable, but...first of all, make sure that isUpdatable is a public property that is (a) on the current DataContext, (b) properly raises a PropertyChanged event when it gets updated (or is a DependencyProperty), and (c) is set to the desired initial value. Your web service call will be asynchronous (web service calls in Silverlight are Async) so if you're using anything other than the vanilla Async Model (where you hook an event prior to making your call and set your value within the event handler - and the event handler is guaranteed to be on the UI thread) you may need to marshal your value back to the UI thread to prevent a nasty exception.
Just remember that because of the async nature of the call, the button will update to its desired value only after the call returns, so set the initial value correctly (enabled or disabled, depending on your needs.)
Here's a quick & dirty sample (the service call merely toggles the value it receives as its parameter):
Codebehind:
public partial class MainPage : UserControl, INotifyPropertyChanged
{
public MainPage()
{
InitializeComponent();
}
private bool _isUpdatable;
public Boolean IsUpdatable
{
get { return _isUpdatable; }
set
{
if (_isUpdatable != value)
{
_isUpdatable = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsUpdatable"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void CallTheService_Click(object sender, RoutedEventArgs e)
{
var serviceProxy = new Service1Client();
serviceProxy.ToggleCompleted += new EventHandler<ToggleCompletedEventArgs>(serviceProxy_ToggleCompleted);
serviceProxy.ToggleAsync(IsUpdatable);
}
private void serviceProxy_ToggleCompleted(object sender, ToggleCompletedEventArgs e)
{
if (e.Error == null)
{
IsUpdatable = e.Result;
}
}
}
XAML:
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding ElementName=window1}">
<Button IsEnabled="{Binding IsUpdatable}" Content="Foo" Height="100" VerticalAlignment="Top"/>
<Button Content="Toggle Foo" Height="100" VerticalAlignment="Bottom" Click="CallTheService_Click" />
</Grid>

WPF MVVM: ICommand Binding to controls

I've totally lost in the command binding that is used in MVVM. How should I bind my object to the window and/or its command to the control to get method called on the Button Click?
Here is a CustomerViewModel class:
public class CustomerViewModel : ViewModelBase
{
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave);
NotifyPropertyChanged("SaveCommand");
}
return _saveCommand;
}
}
public void Save()
{
...
}
public bool CanSave { get { return true; } }
...
ViewModelBase implements the INotifyPropertyChanged interface
Here is how Button is bound to the command:
<Button Content="Save" Margin="3" Command="{Binding DataContext.Save}" />
An instance of the CustomerViewModel is assigned to the DataContext of the window that contains a Button.
The given example is not working: I've put break point into the Save method but execution doesn't pass to the method. I've saw a lot of examples (on the stackoverflow too), but can't figure out how binding should be specified.
Please advise, any help will be appreciated.
Thanks.
P.S. Probably I need to specify RelativeSource in the Button binding... something like this:
Command="{Binding Path=DataContext.Save, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
but which type should be specified for ancestor?
What you are trying to do is to bind directly to the Save method. This is not how to do it.
Assuming that you have set the DataContext of your View to an instance of CustomerViewModel, this is how you bind to the SaveCommand:
<Button Content="Save" Margin="3" Command="{Binding SaveCommand}" />
You do not have to call NotifyPropertyChanged("SaveCommand");.

Resources