C# 将ViewModel方法绑定到视图';s Alt+;F4和关闭按钮
我已经创建了一个自定义方法来关闭视图模型中的表单,并将其绑定到按钮。如何使标题栏中的默认关闭按钮和Alt+F4运行相同的命令C# 将ViewModel方法绑定到视图';s Alt+;F4和关闭按钮,c#,wpf,mvvm,C#,Wpf,Mvvm,我已经创建了一个自定义方法来关闭视图模型中的表单,并将其绑定到按钮。如何使标题栏中的默认关闭按钮和Alt+F4运行相同的命令 public void Close(object parameter) { // Check if any field has been edited if (IsDirty()) { string message = "You have unsaved changes.\n\nAre you sure you want
public void Close(object parameter)
{
// Check if any field has been edited
if (IsDirty())
{
string message = "You have unsaved changes.\n\nAre you sure you want to close this form?";
string title = "Close Window";
MessageBoxResult result = MessageBox.Show(message, title, MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (result == MessageBoxResult.Cancel)
return;
}
employeeWindow.Close();
}
我还是WPF和MVVM的新手,我只是不了解已有的任何解决方案,也不了解如何定制它们来运行上述代码。您正在寻找的是上的事件。它带有一个类型为
bool
的属性,可以设置为true
,这将取消关闭窗口。使用“关闭”按钮关闭窗口并按Alt+F4时,将触发关闭事件
代码隐藏
在代码隐藏场景中,您可以像这样在XAML中添加一个事件处理程序
<Window Closing="OnClosing" ...>
事件触发器(非MVVM)
在MVVM中,您可以安装NuGet软件包,该软件包替代了传统的混合行为(System.Windows.Interactivity
)。您可以使用EventTrigger
将事件绑定到视图模型中的命令。在本例中,您将CancelEventArgs
直接传递给命令
<Window ...>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Closing">
<b:InvokeCommandAction Command="{Binding ClosingCommand}"
PassEventArgsToCommand="True"/>
</b:EventTrigger>
</b:Interaction.Triggers>
<!-- ...other markup. -->
</Window>
然后,使用NuGet包创建一个行为。此行为是可重用的,并封装了与视图模型解耦的关闭逻辑。标题
和消息
依赖项属性允许绑定消息框内容
public class WindowClosingBehavior : Behavior<Window>
{
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register(
nameof(Caption), typeof(string), typeof(WindowClosingBehavior), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
nameof(Message), typeof(string), typeof(WindowClosingBehavior), new PropertyMetadata(string.Empty));
public string Caption
{
get => (string)GetValue(CaptionProperty);
set => SetValue(CaptionProperty, value);
}
public string Message
{
get => (string)GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Closing += OnClosing;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Closing -= OnClosing;
}
private void OnClosing(object sender, CancelEventArgs e)
{
if (!(AssociatedObject.DataContext is IStatefulViewModel statefulViewModel))
return;
if (!statefulViewModel.IsDirty())
return;
e.Cancel = ConfirmClosing();
}
private bool ConfirmClosing()
{
var result = MessageBox.Show(
Message,
Caption,
MessageBoxButton.OKCancel,
MessageBoxImage.Warning,
MessageBoxResult.Cancel);
return result == MessageBoxResult.Cancel;
}
}
公共类WindowClosingBehavior:行为
{
公共静态只读DependencyProperty CaptionProperty=DependencyProperty.Register(
名称(标题)、类型(字符串)、类型(WindowClosingBehavior)、新属性元数据(string.Empty));
公共静态只读DependencyProperty MessageProperty=DependencyProperty.Register(
nameof(消息)、typeof(字符串)、typeof(WindowClosingBehavior)、new PropertyMetadata(string.Empty));
公共字符串标题
{
get=>(字符串)GetValue(CaptionProperty);
set=>SetValue(CaptionProperty,value);
}
公共字符串消息
{
get=>(字符串)GetValue(MessageProperty);
set=>SetValue(MessageProperty,value);
}
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.Closing+=OnClosing;
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
AssociatedObject.Closing-=OnClosing;
}
私有void OnClosing(对象发送方,CancelEventArgs e)
{
如果(!(AssociatedObject.DataContext是IStatefulViewModel statefulViewModel))
回来
如果(!statefulViewModel.IsDirty())
回来
e、 取消=确认关闭();
}
私有布尔确认关闭()
{
var result=MessageBox.Show(
消息
说明文字
MessageBoxButton.ok取消,
MessageBoxImage。警告,
MessageBoxResult.Cancel);
返回结果==MessageBoxResult.Cancel;
}
}
将行为附加到窗口。请注意,您可以在任何窗口上执行此操作
<Window ...>
<b:Interaction.Behaviors>
<local:WindowClosingBehavior Caption="Close Window"
Message="You have unsaved changes. Are you sure you want to close this form?"/>
</b:Interaction.Behaviors>
<!-- ...other markup. -->
</Window>
不要被
和#13混淆
代码>字符,这些是XML中的换行符(\n
)。这是否回答了您的问题?太棒了,这就是我想要的一切,我遵循了你的MVVM行为。感谢您的解释。您所说的“MessageBox是一个视图组件,不能驻留在视图模型中”是什么意思。我的视图是由视图模型创建的,因为如果视图模型无法从数据库加载员工,我不希望创建或显示视图。这不符合MVVM吗?@smally-MVVM是关于从业务逻辑中剥离用户界面。这意味着您的视图模型中不得有任何视图组件引用,无论是窗口
、用户控件
还是任何其他控件。所以不,这是不符合MVVM的。
public interface IStatefulViewModel
{
bool IsDirty();
}
public class MyViewModel : IStatefulViewModel
{
// ...your code.
public bool IsDirty()
{
// ...your checks.
}
}
public class WindowClosingBehavior : Behavior<Window>
{
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register(
nameof(Caption), typeof(string), typeof(WindowClosingBehavior), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
nameof(Message), typeof(string), typeof(WindowClosingBehavior), new PropertyMetadata(string.Empty));
public string Caption
{
get => (string)GetValue(CaptionProperty);
set => SetValue(CaptionProperty, value);
}
public string Message
{
get => (string)GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Closing += OnClosing;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Closing -= OnClosing;
}
private void OnClosing(object sender, CancelEventArgs e)
{
if (!(AssociatedObject.DataContext is IStatefulViewModel statefulViewModel))
return;
if (!statefulViewModel.IsDirty())
return;
e.Cancel = ConfirmClosing();
}
private bool ConfirmClosing()
{
var result = MessageBox.Show(
Message,
Caption,
MessageBoxButton.OKCancel,
MessageBoxImage.Warning,
MessageBoxResult.Cancel);
return result == MessageBoxResult.Cancel;
}
}
<Window ...>
<b:Interaction.Behaviors>
<local:WindowClosingBehavior Caption="Close Window"
Message="You have unsaved changes. Are you sure you want to close this form?"/>
</b:Interaction.Behaviors>
<!-- ...other markup. -->
</Window>