开发者

Adding confirmation dialog to EventToCommand

Laurent,

a common desired behavior when a user selects a button to perform an action is to display a confirmation dialog before performing that action. When this behavior is handled in conjunction with the viewmodel, a good amount of plumbing is required to make this happen. Since this behavior could be considered strictly a GUI issue, I wanted to devise a method that allowed the view to handle confirmation dialogs.

As a result, I have inherited from your EventToCommand class and created EventToCommandWithConfirm. This class calls to a custom messagebox view that I'm not going to include, but I wanted to get your feedback on the concept and whether it's something that could be considered to be included in your toolkit.

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace GalaSoft.MvvmLight.Command
{
    public partial class EventToCommandWithConfirm : EventToCommand
    {

        protected override void Invoke(object parameter)
        {
            // if confirmation is not required, the command can be run immediately
            if (!IsConfirm)
            {
                base.Invoke(parameter);
            }
            else
            {
                switch (ConfirmButtons)
                {
                    case MessageBoxPopUp.Buttons.YesNo:
                    case MessageBoxPopUp.Buttons.YesNoCancel:
                        MessageBoxPopUp.Show(ConfirmMessage, ConfirmCaption , ConfirmButtons, YesAction: () => base.Invoke(parameter));
                        break;
                    case MessageBoxPopUp.Buttons.Ok:
                    case MessageBoxPopUp.Buttons.OkCancel:
                    case MessageBoxPopUp.Buttons.None:
                    default:
                        MessageBoxPopUp.Show(ConfirmMessage, ConfirmCaption, ConfirmButtons, OKAction: () => base.Invoke(parameter));
                        break;
                }

            }            
        }

        public static readonly DependencyProperty IsConfirmProperty = DependencyProperty.Register("Confirm", typeof(bool), typeof(EventToCommandWithConfirm), null);
        public bool IsConfirm
        {
            get { return (bool)GetValue(IsConfirmProperty); }
            set { SetValue(IsConfirmProperty, value); }
        }

        public static readonly DependencyProperty ConfirmCaptionProperty = DependencyProperty.Register("ConfirmCaption", typeof(string), typeof(EventToCommandWithConfirm), null);
        public string ConfirmCaption
        {
     开发者_Python百科       get { return (string)GetValue(ConfirmCaptionProperty); }
            set { SetValue(ConfirmCaptionProperty, value); }
        }

        public static readonly DependencyProperty ConfirmMessageProperty = DependencyProperty.Register("ConfirmMessage", typeof(string), typeof(EventToCommandWithConfirm), null);
        public string ConfirmMessage
        {
            get { return (string)GetValue(ConfirmMessageProperty); }
            set { SetValue(ConfirmMessageProperty, value); }
        }

        public static readonly DependencyProperty ConfirmButtonsProperty = DependencyProperty.Register("ConfirmButtons", typeof(MessageBoxPopUp.Buttons), typeof(EventToCommandWithConfirm), null);
        public MessageBoxPopUp.Buttons ConfirmButtons
        {
            get { return (MessageBoxPopUp.Buttons)GetValue(ConfirmButtonsProperty); }
            set { SetValue(ConfirmButtonsProperty, value); }
        }
    }
}

Example use:

<Button Content="Delete Room..." Height="36" HorizontalAlignment="Left" Margin="279.838,237,0,0" Name="DeleteRoomButton" VerticalAlignment="Top" Width="92" Grid.Column="2">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <confirm:EventToCommandWithConfirm Command="{Binding DeleteRoomClick}" MustToggleIsEnabled="True" ConfirmMessage="{Binding cvsRooms.View.CurrentItem.Description}" ConfirmCaption="Delete Room?" IsConfirm="True"  ConfirmButtons="YesNoCancel"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
</Button>

MessageBoxPopUp.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;

namespace GalaSoft.MvvmLight.Command
{

    public partial class MessageBoxPopUp : ChildWindow
    {

        public enum Buttons
        {
            Ok,
            YesNo,
            OkCancel,
            YesNoCancel,
            None,
        }

        public enum ButtonTypes
        {
            Ok,
            Yes,
            No,
            Cancel,
            Custom,
        }


        private int _buttonCount = 0;
        private Dictionary<int, Button> _buttons = new Dictionary<int, Button>();
        private int _defaultButtonIdx = Int32.MinValue;
        private Action _defaultAction = null;
        private Button _defaultButton = null;

        public string Message
        {
            get { return MessageTextBlock.Text; }
            set { MessageTextBlock.Text = value; }
        }

        public ButtonTypes DefaultButton {get;set;}
        public ButtonTypes ResultButton {get; private set;}
        public int ButtonSelectedIdx { get; private set; }


        public MessageBoxPopUp()
        {  
            InitializeComponent(); 
        }

        /// <summary>
        /// Displays a message box with the specified text, caption, buttons
        /// </summary>
        /// <param name="Message">The text to display in the message box.</param>
        /// <param name="Caption">he text to display in the title bar of the message box.</param>
        /// <param name="Buttons">The set of buttons to display</param>
        /// <param name="DefaultButton">Which button is the default</param>
        /// <param name="Width">Width of the message box</param>
        /// <param name="Height">Height of the message box</param>
        /// <param name="Opacity">Opacity of the message box</param>
        /// <param name="OKAction">Action to perform when the OK button is selected</param>
        /// <param name="CancelAction">Action to perform when the Cancel button is selected</param>
        /// <param name="YesAction">Action to perform when the Yes button is selected</param>
        /// <param name="NoAction">Action to perform when the No button is selected</param>
        /// <param name="MessageBoxToUse">Optional pre-configured instance of window to use.  Use only if custom results are required.</param>
        /// <param name="CustomButton">Any number of custom pairs of button names and associated actions if selected</param>
        public static void Show(String Message, String Caption = "", Buttons Buttons = Buttons.None, ButtonTypes DefaultButton = ButtonTypes.Ok, double Width = Int32.MinValue, double Height = Int32.MinValue, double Opacity = Int32.MinValue, Action OKAction = null, Action CancelAction = null, Action YesAction = null, Action NoAction = null, MessageBoxPopUp MessageBoxToUse = null, params Tuple<string, Action>[] CustomButton)
        {
            MessageBoxPopUp msgBox = MessageBoxToUse != null ? MessageBoxToUse : new MessageBoxPopUp();
            msgBox.ResultButton = ButtonTypes.Cancel;
            if (Width != Int32.MinValue)
                msgBox.Width = Width;
            if (Width != Int32.MinValue)
                msgBox.Height = Height;
            if (Width != Int32.MinValue)
                msgBox.Opacity = Opacity;
            msgBox.Title = Caption;
            msgBox.Message = Message;
            msgBox.ButtonSelectedIdx = -1;


            // create the stock buttons
            if (Buttons == Buttons.Ok || Buttons == Buttons.OkCancel)
                msgBox.CreateButton("Ok", () => { msgBox.ResultButton = ButtonTypes.Ok; if (OKAction != null) msgBox.Closed += (s, e) => OKAction.Invoke(); msgBox.DialogResult = true; }, DefaultButton == ButtonTypes.Ok);
            if (Buttons == Buttons.YesNo || Buttons == Buttons.YesNoCancel)
                msgBox.CreateButton("Yes", () => { msgBox.ResultButton = ButtonTypes.Yes; if (YesAction != null) msgBox.Closed += (s, e) => YesAction.Invoke(); msgBox.DialogResult = true; }, DefaultButton == ButtonTypes.Yes);
            if (Buttons == Buttons.YesNo || Buttons == Buttons.YesNoCancel)
                msgBox.CreateButton("No", () => { msgBox.ResultButton = ButtonTypes.No; if (NoAction != null) msgBox.Closed += (s, e) => NoAction.Invoke(); msgBox.DialogResult = false; }, DefaultButton == ButtonTypes.No);
            if (Buttons == Buttons.YesNoCancel || Buttons == Buttons.OkCancel)
                msgBox.CreateButton("Cancel", () => { msgBox.ResultButton = ButtonTypes.Cancel; if (CancelAction != null) msgBox.Closed += (s, e) => CancelAction.Invoke(); msgBox.DialogResult = false; }, DefaultButton == ButtonTypes.Cancel);
            if (CustomButton != null)
            {
                foreach (Tuple<string, Action> custom in CustomButton)
                {
                    msgBox.CreateButton(custom.Item1, () => { msgBox.ResultButton = ButtonTypes.Custom; if (custom.Item2 != null) msgBox.Closed += (s, e) => custom.Item2.Invoke(); msgBox.DialogResult = true; }, msgBox._buttons.Count == 0);
                }
            }

            // add the buttons to the grid
            resetAndClearGrid(msgBox.ButtonsGrid);
            addColumnDefinitionsToGrid(msgBox.ButtonsGrid, msgBox._buttons.Count);
            for (int i = 0; i < msgBox._buttons.Count; i++)
            {
                addButtonToGrid(msgBox.ButtonsGrid, msgBox._buttons[i], i);
            }
            if (msgBox._defaultButton != null)
                msgBox._defaultButton.Focus();

            msgBox.Show();
        }


        private static void resetAndClearGrid(Grid grid)
        {
            grid.Children.Clear();
            grid.ColumnDefinitions.Clear();
        }

        private static void addColumnDefinitionsToGrid(Grid grid, int columns)
        {
            for (var i = 0; i < columns; i++)
            { grid.ColumnDefinitions.Add(new ColumnDefinition()); }
        }

        private static void addButtonToGrid(Panel grid, UIElement button, int columnIndex)
        {
            grid.Children.Add(button);
            button.SetValue(Grid.ColumnProperty, columnIndex);
        }

        private void CreateButton(String ButtonText, Action ButtonAction, bool IsDefaultButton)
        {
            Button _newButton = new Button
            {
                Content = ButtonText,
                Margin = new Thickness(2)
            };
            int thisButtonIdx = _buttons.Count;
            Action doAction = () => { ButtonSelectedIdx = thisButtonIdx; ButtonAction.Invoke(); };

            _newButton.Click += (sender, args) => 
                doAction.Invoke();
            _buttons.Add(_buttonCount++, _newButton);
            if (IsDefaultButton)
            {
                _defaultButton = _newButton;
                _defaultAction = doAction;
            }
        }

    }
}


I see some positive and some negative in your idea. The positive is that less "plumbing" is needed. The negative is that the MessageBoxPopUp is not configurable.

At MIX11, I am going to present a way to show dialogs which I think is more flexible. I have been using that in multiple WP7 apps and Silverlight apps, and it works quite well. It is a little bit more "plumbing" indeed but it is flexible, easy to test (I will show how at MIX) and can be packed in an assembly for reuse.

Cheers, Laurent

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜