Practical API Design: Confessions of a Java Framework Architect made me pay more attention every time I use/create some API. And I should say that Silverlight API design gives enough reasons to stop over and think about.
This time it was a commanding aspect/API. Lets say you have a very simple form with a button you want to fire a command from. From one side you see the API of IsEnabled, from another Command with its CanExecute:
Question is: Do you expect IsEnabled=False to silently do nothing when Command.CanExecute returns true and button to stay enabled? I didn’t truly expect it, but at least per design I can say I might not be in majority.
I’d rather expect IsEnabled to throw in case when I’m trying to set it to value contradictory to control’s command status.
As a result you can raise a command from a “disabled” button without any problem. |
Following code snippet was used to test the API behavior:
namespace TestCommandVsEnabled
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new SampleViewModel();
}
}
public class SampleViewModel
{
private bool isButtonEnabled;
public bool IsButtonEnabled
{ get { return isButtonEnabled; } set { isButtonEnabled = value; } }
private ICommand sampleCommand = new SampleCommand();
public ICommand SampleCommand
{ get { return sampleCommand; } set { sampleCommand = value; } }
}
public class SampleCommand : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show("command executed");
}
}
}
<Grid x:Name="LayoutRoot" Background="White"> <Button IsEnabled="{Binding IsEnabled, Mode=TwoWay}" Command="{Binding SampleCommand}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="?IsEnabled:" FontSize="16"/> <TextBlock Text="{Binding IsButtonEnabled}" FontSize="16" /> </StackPanel> </Button> </Grid>
Observation in reflector showed that this design is actually “copied” from Prism, although in Prism toggling command.CanExecute would only have once off effect on enabling/disabling the control with subsequent IsEnabled working as expected then. So for example with Prism, changing the order of bindings to:
<Button Command="{Binding SampleCommand}" IsEnabled="{Binding IsEnabled, Mode=TwoWay}">
would lead to have the button disabled. Not anymore with more aggressive/(lax??) SL4 approach though. In my opinion, example of a bad pattern taken to its extreme.
No comments:
Post a Comment