我只是设法让我的 WPF 自定义消息窗口按我的预期工作......几乎:
MessageWindow window;
public void MessageBox()
{
var messageViewModel = new MessageViewModel("Message Title",
"This message is showing up because of WPF databinding with ViewModel. Yay!",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum elit non dui sollicitudin convallis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer sed elit magna, non dignissim est. Morbi sed risus id mi pretium facilisis nec non purus. Cras mattis leo sapien. Mauris at erat sapien, vitae commodo turpis. Nam et dui quis mauris mattis volutpat. Donec risus purus, aliquam ut venenatis id, varius vel mauris.");
var viewModel = new MessageWindowViewModel(messageViewModel, BottomPanelButtons.YesNoCancel);
window = new MessageWindow(viewModel);
viewModel.MessageWindowClosing += viewModel_MessageWindowClosing;
window.ShowDialog();
var result = viewModel.DialogResult;
System.Windows.MessageBox.Show(string.Format("result is {0}", result));
}
void viewModel_MessageWindowClosing(object sender, EventArgs e)
{
window.Close();
}
在底层,有一个“BottomPanel”用户控件,它仅创建一组按钮,其“Visibility”属性由 MessageWindowViewModel 控制(通过诸如“IsOkButtonVisible”之类的属性获取器,它本身由传递的“BottomPanelButtons”枚举的值决定到视图模型的构造函数)。
虽然这满足了我能够在底部显示带有可折叠详细信息和一组可配置按钮的消息窗口的要求,但我对必须将我最初想要的所有功能放入 BottomPanel 控件(或者更确切地说,进入其视图模型),进入 MessageWindowViewModel 类:
public MessageWindowViewModel(MessageViewModel messageViewModel, BottomPanelButtons buttons)
{
_messageViewModel = messageViewModel;
_abortCommand = new DelegateCommand(ExecuteAbortCommand, CanExecuteAbortCommand);
_applyCommand = new DelegateCommand(ExecuteApplyCommand, CanExecuteApplyCommand);
_cancelCommand = new DelegateCommand(ExecuteCancelCommand, CanExecuteCancelCommand);
_closeCommand = new DelegateCommand(ExecuteCloseCommand, CanExecuteCloseCommand);
_ignoreCommand = new DelegateCommand(ExecuteIgnoreCommand, CanExecuteIgnoreCommand);
_noCommand = new DelegateCommand(ExecuteNoCommand, CanExecuteNoCommand);
_okCommand = new DelegateCommand(ExecuteOkCommand, CanExecuteOkCommand);
_retryCommand = new DelegateCommand(ExecuteRetryCommand, CanExecuteRetryCommand);
_yesCommand = new DelegateCommand(ExecuteYesCommand, CanExecuteYesCommand);
Buttons = buttons;
}
/// <summary>
/// Gets/sets a value that determines what buttons appear in the bottom panel.
/// </summary>
public BottomPanelButtons Buttons { get; set; }
public bool IsCloseButtonVisible { get { return Buttons == BottomPanelButtons.ApplyClose || Buttons == BottomPanelButtons.Close; } }
public bool IsOkButtonVisible { get { return Buttons == BottomPanelButtons.Ok || Buttons == BottomPanelButtons.OkCancel; } }
public bool IsCancelButtonVisible { get { return Buttons == BottomPanelButtons.OkCancel || Buttons == BottomPanelButtons.RetryCancel || Buttons == BottomPanelButtons.YesNoCancel; } }
public bool IsYesButtonVisible { get { return Buttons == BottomPanelButtons.YesNo || Buttons == BottomPanelButtons.YesNoCancel; } }
public bool IsNoButtonVisible { get { return IsYesButtonVisible; } }
public bool IsApplyButtonVisible { get { return Buttons == BottomPanelButtons.ApplyClose; } }
public bool IsAbortButtonVisible { get { return Buttons == BottomPanelButtons.AbortRetryIgnore; } }
public bool IsRetryButtonVisible { get { return Buttons == BottomPanelButtons.AbortRetryIgnore || Buttons == BottomPanelButtons.RetryCancel; } }
public bool IsIgnoreButtonVisible { get { return Buttons == BottomPanelButtons.AbortRetryIgnore; } }
public ICommand AbortCommand { get { return _abortCommand; } }
public ICommand ApplyCommand { get { return _applyCommand; } }
public ICommand CancelCommand { get { return _cancelCommand; } }
public ICommand CloseCommand { get { return _closeCommand; } }
public ICommand IgnoreCommand { get { return _ignoreCommand; } }
public ICommand NoCommand { get { return _noCommand; } }
public ICommand OkCommand { get { return _okCommand; } }
public ICommand RetryCommand { get { return _retryCommand; } }
public ICommand YesCommand { get { return _yesCommand; } }
public string AbortButtonText { get { return resx.AbortButtonText; } }
public string ApplyButtonText { get { return resx.ApplyButtonText; } }
public string CancelButtonText { get { return resx.CancelButtonText; } }
public string CloseButtonText { get { return resx.CloseButtonText; } }
public string IgnoreButtonText { get { return resx.IgnoreButtonText; } }
public string NoButtonText { get { return resx.NoButtonText; } }
public string OkButtonText { get { return resx.OkButtonText; } }
public string RetryButtonText { get { return resx.RetryButtonText; } }
public string YesButtonText { get { return resx.YesButtonText; } }
private ICommand _abortCommand;
private ICommand _applyCommand;
private ICommand _cancelCommand;
private ICommand _closeCommand;
private ICommand _ignoreCommand;
private ICommand _noCommand;
private ICommand _okCommand;
private ICommand _retryCommand;
private ICommand _yesCommand;
下面还有更多代码——实际Execute
和CanExecute
处理程序,它们都做同样的事情:设置DialogResult
属性并引发MessageWindowClosing
事件:
private void ExecuteCloseCommand(object commandArgs)
{
DialogResult = DialogResult.Close;
if (MessageWindowClosing != null) MessageWindowClosing(this, EventArgs.Empty);
}
private bool CanExecuteCloseCommand(object commandArgs)
{
return true;
}
现在这有效,但我发现它很难看。我的意思是,我想要的是一个拥有所有 BottomPanel 功能的 BottomPanelViewModel 类。我对此唯一喜欢的是,我没有代码隐藏(除了在 MessageView 类中采用 MessageViewModel 的构造函数,设置 DataContext 属性)。
所以问题是这样的:是否可以重构这段代码,以便我最终得到一个可重用的 BottomPanel 控件,将其功能嵌入到自己的视图模型中并拥有自己的命令?这个想法是让BottomPanel控件上的命令和包含窗口的ViewModel中的处理程序......或者这是否太过分了?
我已经尝试了很多东西(依赖属性,静态命令,......),但我现在拥有的是我可以设法让它在没有代码隐藏的情况下工作的唯一方法。我确信有更好、更专注的做事方式——请原谅我的 WPF 新手,这个“消息框”窗口是我的 WPF“Hello World!”。有史以来第一个项目...