locked
[XAML][VB]ICommand.CanExecute causing inconsistent values for Button.IsEnabled

    Question

  • I have the following ICommand:
    Public Class ClosePopupCommand : Implements ICommand
    	Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements ICommand.CanExecuteChanged
    	Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
    		Return parameter IsNot Nothing AndAlso TypeOf (parameter) Is Popup
    	End Function
    	Public Sub Execute(parameter As Object) Implements ICommand.Execute
    		CType(parameter, Popup).IsOpen = False
    	End Sub
    End Class

    In my XAML I use this command as follows:
    <Button Content="OK" Command="{StaticResource ClosePopup}" CommandParameter="{Binding ElementName=popSelectedPlayer}"/>
    As you can see, CanExecute does nothing more than make sure the parameter is not Nothing and that the parameter is a Popup. However, my Button is sometimes enabled and sometimes disabled, and I can't figure out why it sometimes changes. Shouldn't CanExecute always return True (or at least always the same thing), since popSelectedPlayer is defined in the XAML as a Popup? Any help would be appreciated. Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Wednesday, April 29, 2015 8:26 PM

All replies

  • Hi Nathan,

    >>However, my Button is sometimes enabled and sometimes disabled

    You can catch some information in the CanExecute method, including the type of parameter, if the value of your expression equals to false, just throw a exception and quick check the parameter in visual studio.

    I've tested your code, but I can't reproduce this issue, you can try my suggestion and narrow down the issue.

    If you find something and need more help, could you please share us a simple demo?


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, April 30, 2015 11:37 AM
    Moderator
  • I'm not sure what other code I can provide. I tried adding a System.Diagnostics.Debug.WriteLine() statement in the CanExecute method to display the result, and it seemed very inconsistent, even though I at no point change the parameter. Any ideas? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Friday, May 01, 2015 12:35 AM
  • I'm not sure what other code I can provide. I tried adding a System.Diagnostics.Debug.WriteLine() statement in the CanExecute method to display the result, and it seemed very inconsistent, even though I at no point change the parameter. Any ideas? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/


    Hi Nathan,

    >>I'm not sure what other code I can provide.

    Because I couldn't reproduce this issue on my side, so we need a sample from you to troubleshoot.

    If you still have no idea, I would suggest you recreate a new project and just add a Button and Popup control and implement the command binding to find other possible facts.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, May 04, 2015 9:59 AM
    Moderator
  • I have 2 DataTemplates (which a ContentControl chooses between using a DataTemplateSelector), both of which include Buttons that use the same Command and CommandParameter. The first time one of the DataTemplates is chosen and displayed, the Button is enabled (obviously meaning the Command's CanExecute method returned true, causing the Button's IsEnabled property to be True), and the Button continues to be enabled until the other DataTemplate is chosen by the DataTemplateSelector. After that, the Buttons in both DataTemplates become disabled and never become enabled again. Based on what I have been able to find online, it sounds like CanExecute just needs reevaluated, but I am not sure how or when to do this. I have managed to figure out how to gain access to the Button of the current DataTemplate, so I have access to the Command, CommandParameter, and any other necessary properties of the Button. What and when should I do whatever I need to do to reevaluate CanExecute and update IsEnabled? The XAML for my ContentControl is as follows:
    <Popup x:Name="popSelectedPlayer" Grid.ColumnSpan="3" IsLightDismissEnabled="True">
    	<Border Style="{StaticResource PopupBorderStyle}" Width="Auto"><ContentControl x:Name="cntCardSelection" ContentTemplateSelector="{StaticResource CardSelectionTemplate}"/></Border>
    </Popup>

    My DataTemplateSelector is as follows:
    Public Class PlayerDataTemplateSelector : Inherits DataTemplateSelector
    	Public Property LeftTemplate() As DataTemplate
    	Public Property RightTemplate() As DataTemplate
    	Protected Overrides Function SelectTemplateCore(item As Object) As DataTemplate
    		Return If(item Is Nothing OrElse CInt(item.GetType().GetRuntimeProperty("Index").GetValue(item)) Mod 2 = 0, Me.LeftTemplate, Me.RightTemplate)
    	End Function
    	Protected Overrides Function SelectTemplateCore(item As Object, container As DependencyObject) As DataTemplate
    		Return Me.SelectTemplateCore(item)
    	End Function
    End Class

    Which is included in my Resources as:
    <ctrl:PlayerDataTemplateSelector x:Key="CardSelectionTemplate">
    	<ctrl:PlayerDataTemplateSelector.LeftTemplate>
    		<DataTemplate>
    			<Grid>
    				<Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions>
    				<Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
    				<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" FontFamily="Arial" FontSize="56" Foreground="Black" IsHitTestVisible="False" TextAlignment="Center" Text="{Binding Name}"/>
    				<ItemsControl Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" ItemsSource="{Binding Cards}" Height="{Binding CardCount,Converter={StaticResource HandHeight}}" Margin="{Binding CardCount,Converter={StaticResource HandMargin}}">
    					<ItemsControl.ItemsPanel><ItemsPanelTemplate><Grid/></ItemsPanelTemplate></ItemsControl.ItemsPanel>
    					<ItemsControl.ItemTemplate><DataTemplate><ctrl:Card Value="{Binding Value}" Margin="{Binding Index,Converter={StaticResource CardMargin}}" Tag="{Binding PlayerCardIndex}" Visibility="{Binding Visibility,Converter={StaticResource HideValueVisibility}}" Tapped="Card_Tapped"/></DataTemplate></ItemsControl.ItemTemplate>
    				</ItemsControl>
    				<ctrl:Card Grid.Column="1" Grid.Row="1" Margin="10" Value="{Binding SelectedValue}" Opacity="{Binding SelectedValue,Converter={StaticResource HideValueOpacity}}"/>
    				<Button Grid.Column="1" Grid.Row="2" Style="{StaticResource BasicButton}" Content="OK" Command="{StaticResource ClosePopup}" CommandParameter="{Binding ElementName=popSelectedPlayer}"/>
    			</Grid>
    		</DataTemplate>
    	</ctrl:PlayerDataTemplateSelector.LeftTemplate>
    	<ctrl:PlayerDataTemplateSelector.RightTemplate>
    		<DataTemplate>
    			<Grid>
    				<Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions>
    				<Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
    				<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" FontFamily="Arial" FontSize="56" Foreground="Black" IsHitTestVisible="False" TextAlignment="Center" Text="{Binding Name}"/>
    				<ctrl:Card Grid.Column="0" Grid.Row="1" Margin="10" Value="{Binding SelectedValue}" Opacity="{Binding SelectedValue,Converter={StaticResource HideValueOpacity}}"/>
    				<Button Grid.Column="0" Grid.Row="2" Style="{StaticResource BasicButton}" Content="OK" Command="{StaticResource ClosePopup}" CommandParameter="{Binding ElementName=popSelectedPlayer}"/>
    				<ItemsControl Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" ItemsSource="{Binding Cards}" Height="{Binding CardCount,Converter={StaticResource HandHeight}}" Margin="{Binding CardCount,Converter={StaticResource HandMargin}}">
    					<ItemsControl.ItemsPanel><ItemsPanelTemplate><Grid/></ItemsPanelTemplate></ItemsControl.ItemsPanel>
    					<ItemsControl.ItemTemplate><DataTemplate><ctrl:Card Value="{Binding Value}" Margin="{Binding Index,Converter={StaticResource CardMargin}}" Tag="{Binding PlayerCardIndex}" Visibility="{Binding Visibility,Converter={StaticResource HideValueVisibility}}" Tapped="Card_Tapped"/></DataTemplate></ItemsControl.ItemTemplate>
    				</ItemsControl>
    			</Grid>
    		</DataTemplate>
    	</ctrl:PlayerDataTemplateSelector.RightTemplate>
    </ctrl:PlayerDataTemplateSelector>

    And my command is defined as follows:
    Public Class ClosePopupCommand : Implements ICommand
    	Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements ICommand.CanExecuteChanged
    	Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
    		Return parameter IsNot Nothing AndAlso TypeOf (parameter) Is Popup
    	End Function
    	Public Sub Execute(parameter As Object) Implements ICommand.Execute
    		CType(parameter, Popup).IsOpen = False
    	End Sub
    End Class

    Any ideas on how to keep the Buttons' IsEnabled properties up to date? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/


    Tuesday, May 05, 2015 7:54 PM
  • I have the following Command that I use for several Buttons:

    Public Class ClosePopupCommand : Implements ICommand
    	Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements ICommand.CanExecuteChanged
    	Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
    		Return parameter IsNot Nothing AndAlso TypeOf (parameter) Is Popup
    	End Function
    	Public Sub Execute(parameter As Object) Implements ICommand.Execute
    		CType(parameter, Popup).IsOpen = False
    	End Sub
    End Class

    And I have the following Popup in my XAML:

    <Popup x:Name="popSelectedPlayer" Grid.ColumnSpan="3" IsLightDismissEnabled="True">
    	<Border Style="{StaticResource PopupBorderStyle}" Width="Auto">
    <ContentControl x:Name="cntCardSelection" ContentTemplateSelector="{StaticResource CardSelectionTemplate}"/>
    </Border> </Popup>

    You will notice that the ContentControl uses the ContentTemplateSelector property, which returns one of two DataTemplates, both of which contain a Button with the following XAML:

    <Button Grid.Column="1" Grid.Row="2" Style="{StaticResource BasicButton}" Content="OK" Command="{StaticResource ClosePopup}" CommandParameter="{Binding ElementName=popSelectedPlayer}"/>

    The IsEnabled properties of these two Buttons seems very strange. The pattern I have noticed while trying to figure out my problem is that the first time I open the Popup, the Button (regardless of which ContentTemplate the ContentTemplateSelector chose first) is enabled, which means the Command's CanExecute function returned True. This Button continues to be enabled until the other ContentTemplate is chosen by the ContentTemplateSelector, whose Button is disabled. Then, the Buttons for both ContentTemplates are, and continue to be, disabled. Here is a basic summary of what happens:

    The Button on the first ContentTemplate chosen by the ContentTemplateSelector is enabled

    The Button on the first ContentTemplate chosen by the ContentTemplateSelector continues to be enabled

    The Button on the second ContentTemplate chosen by the ContentTemplateSelector is disabled

    The Button on the first ContentTemplate chosen by the ContentTemplateSelector is disabled

    As you can see, both Buttons are disabled after switching to the second ContentTemplate (it doesn't matter which ContentTemplate is first or second, the pattern is the same). I think that this has something to do with CanExecute being evaluated before the Popup is loaded (causing the "parameter" argument to be Nothing and therefore causing CanExecute to return False). But I have tried everything I can come up with. What can I do to reevaluate CanExecute? The CanExecuteChanged event doesn't seem to be very useful. Any help would be appreciated. Thanks.


    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Monday, May 11, 2015 4:21 PM
  • I have found several sites that suggest that this is related to the DataContext. But even after looking at all the examples they showed, I still could not get mine to work. Maybe mentioning DataContext can help some of you come up with a solution? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Monday, May 11, 2015 9:39 PM