A question I asked myself the other day was 'what is the most elegant way to show a confirm dialogue to a user?' Now there's nothing hard about
doing this and we all do it from time to time, but nevertheless there are many different ways one might go about doing it. My particular concern
was firstly to invoke ICommands from the user action and secondly avoid triggering UI events from my presenter (i.e. opening dialogues).
The first and most obvious technique is to simply show a confirm in the event handler of the button in code behind.
Take the following XAML:
<data:DataGrid ItemsSource="{Binding Categories}" AutoGenerateColumns="False">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="ID" Binding="{Binding CategoryID}" />
<data:DataGridTextColumn Header="Name" Binding="{Binding CategoryName}" />
<data:DataGridTemplateColumn Header="">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" Click="Button_Click" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
and the click handler in the code-behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
Category cat = (sender as Button).DataContext as Category;
if (HtmlPage.Window.Confirm("Are you sure you want to delete that?"))
{
HtmlPage.Window.Alert("Deleted");
}
}
This works perfectly well, and looks something like this:

Not a good solution in my case, however, as I wanted to use commanding to link my Delete button to an ICommand in the view’s presenter. (Prism gives a great implementation of ICommand – DelegateCommand<T>).
When you use commanding, the obvious place to put the confirm dialogue is in the presenter:
<data:DataGrid ItemsSource="{Binding Categories}" AutoGenerateColumns="False">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="ID" Binding="{Binding CategoryID}" />
<data:DataGridTextColumn Header="Name" Binding="{Binding CategoryName}" />
<data:DataGridTemplateColumn Header="">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" cal:Click.Command="{Binding Path=Value, Source={StaticResource DeleteCommand}}"
cal:Click.CommandParameter="{Binding}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
and the DelegateCommand in the presenter:
DeleteCommand = new DelegateCommand<Category>((cat) =>
{
if (HtmlPage.Window.Confirm("Are you sure you want to delete that?"))
{
HtmlPage.Window.Alert("Deleted");
}
});
NOTE: Of course there’s an obvious problem with binding to an ICommand inside a DataTemplate – the DataContext is not the view (e.g. the view model or presenter) but the particular data item that the DataTemplate is displaying. You can get around this using RelativeSource binding in WPF, but not in Silverlight. The solution is to make your ICommand a StaticResource using a implementation of ObservableCommand, as described here: http://msdn.microsoft.com/en-us/library/dd458928.aspx
Now in the example above, the confirm dialogue certainly displays as I’d like it to, but I have philosophical objections to taking UI components (i.e. the dialogue) out of the view and sticking it in the presenter. Doing this also makes unit testing in the presenter a lot more difficult.
The first alternative that came to mind was to use the code-behind again, but this time invoke the ICommand from there, like this:
private void Click1(object sender, RoutedEventArgs e)
{
((HomePagePresenter)DataContext).DeleteCommand.Execute((sender as Button).DataContext as Category);
}
This is actually a fairly nice solution- the separation between the presenter and the view is maintained, the inconvenience of declaring the ICommand as a StaticResource is avoided, and it’s quite intuitive. It still seems a little inelegant, however – since all XAML purists will tell you that binding is better in every case.
The next solution I implemented is really nice. I created a new attached behaviour that extends Prism’s CommandBehaviorBase<T> called ConfirmClick. This lets me use the following mark-up:
<data:DataGrid ItemsSource="{Binding Categories}" AutoGenerateColumns="False" Grid.Row="1">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="ID" Binding="{Binding CategoryID}" />
<data:DataGridTextColumn Header="Name" Binding="{Binding CategoryName}" />
<data:DataGridTemplateColumn Header="">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" cal2:ConfirmClick.Command="{Binding Path=Value, Source={StaticResource DeleteCommand}}"
cal2:ConfirmClick.CommandParameter="{Binding}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
I won’t include the two files ButtonBaseConfirmClickCommandBehavior.cs & ConfirmClick.cs here as they are quite lengthy, but download the source code at the end of this post if you want them.
This approach totally abstracts the out the creation of the confirm dialogue so I don’t have to think about it at all. It’s neat, reusable and fits the pattern perfectly.
I could have stopped here, but there was one other avenue I wanted to check: the new Behaviours that come as part of Silverlight 3. Behaviours are divided into three broad categories: Triggers, Actions and Behaviors. In my case, I can use the inbuilt EventTrigger trigger and attach it to the Click event of my Button.
Don’t forget that if you want to use Behaviors, you need to reference Microsoft.Expression.Interactivity.dll from you project and import the namespace into the XAML.
Now that I can trap the Interestingly, the Microsoft.Expression.Interactivity implements an InvokeCommandAction which I couldn’t for the life of me get to work. It doesn’t help that it is not mentioned anywhere in the Silverlight 3 documentation. Not to worry, I ended up implementing my own Action which looks for an ICommand in the FrameworkElement.Tag property. Here’s the XAML:
<data:DataGrid ItemsSource="{Binding Categories}" AutoGenerateColumns="False" Grid.Row="2">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="ID" Binding="{Binding CategoryID}" />
<data:DataGridTextColumn Header="Name" Binding="{Binding CategoryName}" />
<data:DataGridTemplateColumn Header="">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" Tag="{Binding Path=Value, Source={StaticResource DeleteCommand}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<loc:ConfirmCommandAction />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
And the Action looks like this:
public class ConfirmCommandAction : TriggerAction<FrameworkElement>
{
private string message;
public string Message
{
get { return message ?? "Are you sure you want to do that?"; }
set { message = value; }
}
protected override void Invoke(object parameter)
{
if (AssociatedObject.Tag is ICommand)
{
var cmnd = AssociatedObject.Tag as ICommand;
if (cmnd != null && cmnd.CanExecute(AssociatedObject.DataContext))
{
if (HtmlPage.Window.Confirm(Message))
{
cmnd.Execute(AssociatedObject.DataContext);
}
}
}
}
}
I should point out that my implementation of ConfirmCommandAction was pretty rapid and has some holes in it. For instance, I’m not sure I like assuming that the DataContext of the AssociatedObject should be passed as the parameter of the ICommand. I’m also a little unsure whether the Tag property was really supposed to be used like that. Nevertheless it all works quite nicely.
So, there’s several techniques for implementing a confirm dialogue on an ICommand. I think each is valid in it’s own way, but my money is on the ConfirmClick attached behaviour as the most elegant solution – providing you’re willing to include some of the Prism libraries in your project.
Hope you find it useful!
Get the source