WPF随笔(十四)--如何在MVVM模式下关闭窗口
程序员文章站
2022-03-07 14:18:36
...
离上一篇WPF随笔有多久,再度编码WPF项目就有多久。机缘巧合又接下了一个开发WPF桌面程序的任务,又有机会详细研究之前一直忽略的细节。
今天就来谈谈如何在MVVM模式下关闭窗口。
什么?关闭窗口还要写代码?点个×不就行了?
起初我也是这么想的, 然而实践证明并没有那么简单。
1.需求场景描述
在主窗口(一般默认是MainWindow)打开子窗口ChildWindow,在子窗口中进行数据的新增或编辑操作,点击自定义的“保存”按钮,在数据保存完成后自动关闭当前子窗口。
需求非常简单,如果使用路由事件那将会非常简单。但使用MVVM模式就意味着View视图层与ViewModel视图模型层的分离,直接添加路由事件不太现实。
2.解决方案
通用的解决方案有很多,网上一搜一大堆,大体思路都一样。结合MVVM模式的思想和WPF的自身特性,一是从Binding绑定着手,二是不能在xaml.cs里写路由事件就在ViewModel里实现路由事件。
2.1 从绑定着手
子窗口ChildWindow的xaml代码片段
<Button Command="{Binding SaveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}}">
<Button.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<icon:PackIconModern Width="12" Height="12" HorizontalAlignment="Center" VerticalAlignment="Center" Kind="Save"></icon:PackIconModern>
<TextBlock Margin="3,0,0,0">保存</TextBlock>
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
其中绑定参数CommandParameter是重点,表达式的含义是找到当前的窗口。
ViewModel层ChildViewModel.cs的命令定义:
//保存命令,传递参数为窗口类型
public DelegateCommands<System.Windows.Window> SaveCommand { get; set; }
ChildViewModel.cs的命令对应方法实现
private async void Save(System.Windows.Window obj)
{
///
///你的业务逻辑代码
///
var win = obj;
win.Close();
}
2.2 从路由事件着手
MVVM模式下在xaml.cs里面写路由事件那味道就不对了,但是ViewModel层也可以写代码实现路由事件。
ChildViewModel.cs里的代码片段:
public ChildViewModel()
{
//你的初始化代码
System.Windows.EventManager.RegisterClassHandler(typeof(System.Windows.Controls.Button), System.Windows.Controls.Button.ClickEvent, new System.Windows.RoutedEventHandler(SaveButtonClicked));
}
private void SaveButtonClicked(object sender, RoutedEventArgs e)
{
///你的业务逻辑代码
System.Windows.Controls.Button btn = (System.Windows.Controls.Button)e.Source;
var win = FindVisualParent<Window>(btn)[0];
win.Close();
}
其中通过可视化数据查找指定父级元素的方法为:
/// 利用VisualTreeHelper寻找指定依赖对象的父级对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static List<T> FindVisualParent<T>(DependencyObject obj) where T : DependencyObject
{
try
{
List<T> TList = new List<T> { };
DependencyObject parent = VisualTreeHelper.GetParent(obj);
if (parent != null && parent is T)
{
TList.Add((T)parent);
List<T> parentOfParent = FindVisualParent<T>(parent);
if (parentOfParent != null)
{
TList.AddRange(parentOfParent);
}
}
else if (parent != null)
{
List<T> parentOfParent = FindVisualParent<T>(parent);
if (parentOfParent != null)
{
TList.AddRange(parentOfParent);
}
}
return TList;
}
catch (Exception)
{
return null;
}
}
注重小细节,掌握大知识
上一篇: etcd集群部署