我有一个浮动窗口模板,我在其中通过初始化MessageBoxViewModel对象来加载一个消息框以显示消息
我想在用户点击“关闭”按钮时关闭此弹出窗口。我该怎么做 我在MessageBoxViewModel中编写了Close按钮命令。
public class MessageBoxViewModel : ViewModelBase
{
public MessageBoxViewModel ( string messageText)
{
// load all the fields
}
}
private string message;
public string Message
{
get
{
return message;
}
set
{
if (value == message)
return;
message = value;
base.OnPropertyChanged("Message");
}
}
#region Commands
RelayCommand okay;
public ICommand OKAY
{
get
{
if (okay == null)
{
okay = new RelayCommand(
param => this.CallOkay()
);
}
return okay;
}
}
#endregion
void CallOkay()
{
// should write logic to close this window
}
答案 0 :(得分:0)
MVVM的本质规定模型对正在读取它的窗口一无所知。
解决方案是视图模型抛出一个事件供Window处理。
在您的视图模型代码中:
public event EventHandler CallOkayRequested;
void CallOkay()
{
var dg = this.CallOkayRequested;
if(dg != null)
{
dg(this, EventArgs.Empty);
}
}
在您的窗口代码中,处理此事件:
MyMessageBox()
{
InitializeComponent();
((MessageBoxViewModel)this.DataContext).CallOkayRequested += ModelCallOkayRequested;
}
void ModelCallOkayRequested(object sender, EventArgs args)
{
this.Close();
}
这可能是最好的方法,例如,如果视图模型在想要关闭对话框之前执行其他一些操作。
<小时/> 但是,如果视图模型除了中继请求之外什么都不做,那么如果您完全绕过模型并使用标准
RoutedUICommand
,则代码更少。
在您的XAML中声明命令绑定:
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandExecuted" />
</Window.CommandBindings>
将此命令附加到您的按钮:
<Button Command="ApplicationCommands.Close">
Close
</Button>
并在窗口代码中处理close方法:
private void CloseCommandExecuted(object sender, EventArgs args)
{
this.Close();
}
答案 1 :(得分:0)
Sriram Sakthivel的评论中提到了很多方法。但使用视图模型事件最简单:
public event Action ViewModelClosed;
void CallOkay()
{
if (ViewModelClosed != null) ViewModelClosed();
}
在MessageBox的代码中:
...
MessageBoxViewModel vm = new MessageBoxViewModel();
vm.ViewModelClosed += () => this.Close();
我总是在我的视图中使用一层消息框,如下所示:
<UserControl>
<Grid>
<Border>
<!-- contents of my control -->
</Border>
<Border Visibility="{Binding IsVisible,
Converter={StaticResource BooleanToVisibilityConverter}}"
Background="#4000">
<!-- contents of my message box -->
</Border>
</Grid>
</UserControl>
将一个布尔(IsVisible)属性添加到MessageBoxViewModel
并将MessageBox的Visibility绑定到它。然后只需在CallOkay()
答案 2 :(得分:0)
另一个MVVM框架使用的方法(Caliburn Micro)实际上只是使用来自VM的事件。
然而,为了将想法扩展到可重用的“模块”,Caliburn Micro使用Conductor
类来管理View的生命周期与ViewModel的生命周期之间的关系。 ViewModel上的一个接口将其标记为“可关闭”,并且您需要编写特定于您正在使用的窗口/对话框实现的指挥(假设它不是标准Window
的子类)。
在代码中的某处,您必须创建一个窗口并将其绑定到viewmodel。这是创建导体以管理关系的地方(Caliburn在其IWindowManager
实现中具有此功能,当Window
/ {{ShowPopup
实现时,ShowDialog
实例提供并绑定public class WindowConductor
{
private ISupportClose _closeable;
private Window _window;
private bool _closingFromViewModel;
private bool _closingFromView;
public WindowConductor(Window view, ISupportClose closeable)
{
_closeable = closeable;
_window = view;
_window.Closed += WindowClosed;
_closeable.Closed += ViewModelClosed;
}
public void WindowClosed(object sender, EventArgs e)
{
if(_closingFromViewModel) return;
_closingFromView = true;
closeable.Close();
}
public void ViewModelClosed(object sender, EventArgs e)
{
if(_closingFromView) return;
_closingFromViewModel = true;
window.Close();
}
}
实例1}}方法被称为
指挥可能看起来像(一个人为的例子):
ISupportClose
您的public interface ISupportClose
{
event EventHandler<CloseEventArgs> Closed;
void Close();
}
界面可以是:
public void CreateWindow(viewModel)
{
Window window = new Window();
window.DataContext .. // etc etc bind up the view/model
// Wrap the window/vm with the conductor if the view supports the interface
var closeable = viewModel as ISupportClose;
if(closeable != null)
new WindowConductor(window, closeable);
}
然后,当您创建窗口以显示VM的视图时:
Screen
我总觉得这非常有用,因为它将问题分成了更小的块。无论如何,您通常不会在应用程序中使用超过1个窗口的实现。
可能值得注意的是,所有这些背后都有一些管道代码(实际上基类{{1}}提供了生命周期管理的标准实现等)。
如果你没有使用MVVM框架,我强烈建议你这样做 - 编写样板'胶水'已经由多个框架完成了