将确认对话框添加到EventToCommand

时间:2011-03-24 16:42:33

标签: mvvm-light

劳伦,

当用户选择按钮来执行操作时,常见的期望行为是在执行该操作之前显示确认对话框。当与viewmodel一起处理此行为时,需要大量的管道才能实现此目的。由于此行为可以严格地视为GUI问题,因此我想设计一种允许视图处理确认对话框的方法。

结果,我从EventToCommand类继承并创建了EventToCommandWithConfirm。这个类调用了一个我不打算包含的自定义消息框视图,但是我希望得到你对这个概念的反馈,以及它是否可以被认为包含在你的工具包中。

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
        {
            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); }
        }
    }
}

使用示例:

<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;
            }
        }

    }
}

1 个答案:

答案 0 :(得分:0)

我认为你的想法有些积极而且有些消极。积极的是,需要较少的“管道”。否定的是MessageBoxPopUp是不可配置的。

在MIX11,我将展示一种方式来显示我认为更灵活的对话框。我一直在多个WP7应用程序和Silverlight应用程序中使用它,它运行得很好。它确实有点“管道”,但它很灵活,易于测试(我将在MIX上展示)并且可以打包在一个组件中以便重复使用。

干杯, 劳伦