I'm trying to build a behavior that disables the button and changes the text to follow the common pattern of disabling a button to stop a user from double clicking. I need the behavior changes to take effect before the commmand. Can I use a behavior this way?
view: (set the DataContext in the loaded event of the code behind)
<Grid x:Name="LayoutRoot" Background="White">
<Button Height="50" Width="150" Content="Save" Command="{Binding ButtonClickedCommand}" IsEnabled="{Binding IsNextButtonEnabled}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<behaviors:SubmitButtonBehavior LoadingButtonText="WAIT!!!..." IsEnabled="True" IsFinished="{Binding IsFinishedSubmitButtonBehavior}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
ViewModel
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
namespace SubmitButtonBehaviorTest
{
public class MainPageViewModel : ViewModelBase
{
///
/// Private isFinishedSubmitButtonBehavior property.
///
private bool isFinishedSubmitButtonBehavior;
public bool IsFinishedSubmitButtonBehavior
{
get
{
return this.isFinishedSubmitButtonBehavior;
}
set
{
this.isFinishedSubmitButtonBehavior = value;
this.RaisePropertyChanged("IsFinishedSubmitButtonBehavior");
}
}
/// <summary>
/// Private ButtonClickedCommand property.
/// </summary>
private RelayCommand buttonClickedCommand;
public RelayCommand ButtonClickedCommand
{
get
{
return this.buttonClickedCommand;
}
private set
{
this.buttonClickedCommand = value;
}
}
public MainPageViewModel()
{
this.ButtonClickedCommand = new RelayCommand(
() =>
{
MessageBox.Show("Clicked");
this.IsFinishedSubmitButtonBehavior = true;
});
}
}
}
Behavior:
namespace SubmitButtonBehaviorTest.Behaviors
{ using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity;
/// <summary>
/// Attach this behavior to disable the button on click and change the text
/// </summary>
public class SubmitButtonBehavior : TriggerAction<UIElement>
{
/// <summary>
/// The original button text, reset when the IsEnabled is set back.
/// </summary>
public string OriginalButtonText { get; set; }
/// <summary>
/// Gets or sets the loading button text.
/// </summary>
/// <value>The loading button text.</value>
public string LoadingButtonText { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [change button text].
/// </summary>
/// <value><c>true</c> if [change button text]; otherwise, <c>false</c>.</value>
public bool ChangeButtonText { get; set; }
/// <summary>
/// Set this to true when the operation is finished.
/// </summary>
/// <value>
/// <c>true</c> if this instance is finished; otherwise, <c>false</c>.
/// </value>
public bool IsFinished
{
get { return (bool)GetValue(IsFinishedProperty); }
set
{
SetValue(IsFinishedProperty, value);
this.OnIsFinishedChanged();
}
}
/// <summary>
/// Called when [is finished change].
/// </summary>
/// <param name="value">if set to <c>true</c> [value].</param>
private void OnIsFinishedChanged()
{
if (this.AssociatedObject != null && !((Button)this.AssociatedObject).IsEnabled)
{
((Button)this.AssociatedObject).IsEnabled = true;
((Button)this.AssociatedObject).Content = this.OriginalButtonText;
}
}
// Using a DependencyProperty as the backing store for IsFinished. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsFinishedProperty =
DependencyProperty.Register("IsFinished", typeof(bool), typeof(SubmitButtonBehavior), new PropertyMetadata(false));
/// <summary>
/// Initializes a new instance of the <see cref="SubmitButtonBehavior"/> class.
/// </summary>
public SubmitButtonBehavior()
{
// defaults
this.ChangeButtonText = true;
this.LoadingButtonText = "Please Wait...";
// AssociatedObject is empty at initialization this.originalButtonText = this.AssociatedObject.Content.ToString();
}
protected override void Invoke(object parameter)
{
if (this.IsEnabled)
{
Button clickedButton = ((Button)this.AssociatedObject);
clickedButton.IsEnabled = false;
this.OriginalButtonText = clickedButton.Content.ToString();
if (this.ChangeButtonText)
{
clickedButton.Content = this.LoadingButtonText;
}
}
}
}
}
EDIT: Suggestion with disable through CanExecute. The button text still does not change. Also I would still like to make this a reusable behavior, but this could be a good approach as well.
this.ButtonClickedCommand = new RelayCommand<Button>(
(clickedButton) =>
{
string originalText = clickedButton.Content.ToString();
this.IsSubmitting = true;
clickedButton.Content = "Please Wait...";
MessageBox.Show("Clicked");
this.IsFinishedSubmitButtonBehavior = true;
this.IsSubmitting = false;
clickedButton.Content = originalText;
},
(clickedButton) =>
{
return !this.IsSubmitting;
}
);
Edit: I've found a good solution using messaging and added that as an answer to my own question.