开发者

How can I get a behavior to fire before a command in Silverlight - disable double clicking?

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.


As Dan commented you are probably better off using CanExecute to implement your disable logic. As for changing button text I would recommend using a binding to this.IsSubmitting through a ValueConverter that chooses the correct text. This minimizes the interaction between your ViewModel and the View in that all the ViewModel does is say I'm submitting and the View will read that and display the correct text.


I've found a better solution than behaviors by using the MvvmLight toolkit Messaging. 1. create a key in your MainPage.xaml.cs 2. register for the message in the constructor using the key

    GalaSoft.MvvmLight.Extras.SL4.Messenger.Default.Register<NotificationMessage>(this, 
MainPage.EnableButtonKey, message =>{                   
// send true if submitting, false if finished
          // Save or Saving is default
          this.SaveButton.IsEnabled = message.Content;

this.SaveButton.Content = message.Notification; }); } ));

  1. Send a message to enable or disable the button such as : Messenger.Default.Send>(new NotificationMessage(this, false, "Please Wait..."), MainPage.SubmitKey); // re-enable Messenger.Default.Send>(new NotificationMessage(this, true, originalButtonText), MainPage.SubmitKey);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜