During BASTA Austria I have been asked a WPF question. How can I implement a confirmation question that is asked whenever a user checks a CheckBox? Imagine the following dialog:
Our goal is to display an "Are you sure?" message if the user checks "Delete everything!" or hits the "Delete Everything (in Code)" button. There should not be a message box if the user unchecks the "Delete everything!" check box.
XAML Source (Without Confirmation Message)
Here you see the XAML source with which we start:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<CheckBox Content="Delete everything!" Name="DeleteEverythingCheckbox" IsChecked="{Binding Path=CheckboxChecked}"
Margin="5">
</CheckBox>
<Button Command="{Binding Path=SetDeleteEverythingCommand}" Margin="5">Delete Everything (in Code)</Button>
<TextBox IsEnabled="{Binding ElementName=DeleteEverythingCheckbox, Path=IsChecked}" Text="Here is some text to edit"
Margin="5"/>
</StackPanel>
</Window>
The code behind file just connects to the view model:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
}
And finally here is the view model (I use Prism's NotificationObject class as the base class to get an implementation of INotifyPropertyChanged):
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using System.Windows.Input;
namespace WpfApplication1
{
public class MainWindowViewModel : NotificationObject
{
public MainWindowViewModel()
{
this.SetDeleteEverythingCommand = new DelegateCommand(() =>
{
this.CheckboxChecked = true;
},
() => !this.CheckboxChecked);
}
private bool CheckboxCheckedValue = default(bool);
public bool CheckboxChecked
{
get { return this.CheckboxCheckedValue; }
set
{
if (this.CheckboxCheckedValue != value)
{
this.CheckboxCheckedValue = value;
this.RaisePropertyChanged(() => this.CheckboxChecked);
}
}
}
public ICommand SetDeleteEverythingCommand { get; private set; }
}
}
Add a TriggerAction for Showing Confirmation Message
System.Windows.Interactivity defines a class TriggerAction<T> which we can use to provide a mechanism for adding the confirmation message in XAML. The code is quite simple:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace WpfApplication1
{
public class ConfirmInvokeCommandAction : TriggerAction<DependencyObject>
{
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(ConfirmInvokeCommandAction), new PropertyMetadata("Are you sure?"));
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
protected override void Invoke(object parameter)
{
var checkBox = this.AssociatedObject as CheckBox;
if (checkBox != null)
{
if (MessageBox.Show(this.Message, "Alert", MessageBoxButton.YesNo) == MessageBoxResult.No)
{
checkBox.IsChecked = false;
}
}
}
}
}
We use an event trigger (mechanism defined in the Expression SDK) to access our TriggerAction in XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<CheckBox Content="Delete everything!" Name="DeleteEverythingCheckbox" IsChecked="{Binding Path=CheckboxChecked}"
Margin="5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<local:ConfirmInvokeCommandAction Message="Are you sure?" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
<Button Command="{Binding Path=SetDeleteEverythingCommand}" Margin="5">Delete Everything (in Code)</Button>
<TextBox IsEnabled="{Binding ElementName=DeleteEverythingCheckbox, Path=IsChecked}" Text="Here is some text to edit"
Margin="5"/>
</StackPanel>
</Window>
Result
This does the trick:
If you want to try the solution, download the source code.
comments powered by