劳伦,
当用户选择按钮来执行操作时,常见的期望行为是在执行该操作之前显示确认对话框。当与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;
}
}
}
}
答案 0 :(得分:0)
我认为你的想法有些积极而且有些消极。积极的是,需要较少的“管道”。否定的是MessageBoxPopUp是不可配置的。
在MIX11,我将展示一种方式来显示我认为更灵活的对话框。我一直在多个WP7应用程序和Silverlight应用程序中使用它,它运行得很好。它确实有点“管道”,但它很灵活,易于测试(我将在MIX上展示)并且可以打包在一个组件中以便重复使用。
干杯, 劳伦