C# WPF点击窗体内嵌页面按钮隐藏当前窗口打开新窗口问题
WPF 内嵌页面按钮点击隐藏宿主窗口实现方案
问题场景
现有WPF窗体使用DockPanel承载Page实现导航功能,需求为点击内嵌Page上的按钮时,隐藏当前宿主窗口、弹出新窗口,原有实现代码未生效。
原有问题代码
Page端按钮代码
public partial class SubPnlItems_SK : Page { public SubPnlItems_SK() { InitializeComponent(); } private void btnAddItems_SK_Click(object sender, RoutedEventArgs e) { PnlTabMenu_SK tabMenu_SK = new PnlTabMenu_SK(); PnlAddItem_SK pnlAddItem_SK = new PnlAddItem_SK(); tabMenu_SK.Visibility = Visibility.Hidden; pnlAddItem_SK.ShowDialog(); } private void btnViewItems_SK_Click(object sender, RoutedEventArgs e) { } }
宿主窗口代码
public partial class PnlTabMenu_SK : Window { public PnlTabMenu_SK() { InitializeComponent(); dockPanel_SK.NavigationService.Navigate(new Uri("SubPnlItems_SK.xaml", UriKind.Relative)); } private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { this.DragMove(); } private void btn_minimize_Click(object sender, RoutedEventArgs e) { WindowState = WindowState.Minimized; } private void btn_close_Click(object sender, RoutedEventArgs e) { this.Close(); } private void btnItems_SK_Click(object sender, RoutedEventArgs e) { dockPanel_SK.NavigationService.Navigate(new Uri("SubPnlItems_SK.xaml", UriKind.Relative)); } private void btnISN_SK_Click(object sender, RoutedEventArgs e) { dockPanel_SK.NavigationService.Navigate(new Uri("SubPnlISN_SK.xaml", UriKind.Relative)); } private void btnMRF_SK_Click(object sender, RoutedEventArgs e) { dockPanel_SK.NavigationService.Navigate(new Uri("SubPnlMRF_SK.xaml", UriKind.Relative)); } private void btnGRN_SK_Click(object sender, RoutedEventArgs e) { dockPanel_SK.NavigationService.Navigate(new Uri("SubPnlGRN_SK.xaml", UriKind.Relative)); } }
失效原因
代码核心错误:按钮点击事件中通过new PnlTabMenu_SK()创建的是一个从未被显示过的全新窗口实例,和当前已经打开、承载Page的宿主窗口完全无关,对这个新实例设置隐藏属性自然不会产生任何效果。
修复方法
快速实现:直接获取当前Page所属的宿主窗口
WPF的Page类可以通过Window.GetWindow()方法直接获取承载自身的父窗口实例,不需要手动新建,修改按钮点击逻辑即可:
private void btnAddItems_SK_Click(object sender, RoutedEventArgs e) { // 获取当前Page实际挂载的宿主窗口实例 PnlTabMenu_SK hostWindow = Window.GetWindow(this) as PnlTabMenu_SK; if (hostWindow == null) return; PnlAddItem_SK pnlAddItem_SK = new PnlAddItem_SK(); hostWindow.Visibility = Visibility.Hidden; // 弹窗关闭后自动恢复宿主窗口显示,不需要可删除 pnlAddItem_SK.Owner = hostWindow; pnlAddItem_SK.ShowDialog(); hostWindow.Visibility = Visibility.Visible; }
解耦实现:事件通知(符合MVVM规范)
如果不希望Page直接依赖具体宿主窗口类型,避免耦合,可以通过事件回调让宿主窗口自行处理显示隐藏逻辑:
- 在Page类中定义点击事件
public partial class SubPnlItems_SK : Page { // 新增按钮点击事件 public event EventHandler AddItemsRequested; public SubPnlItems_SK() { InitializeComponent(); } private void btnAddItems_SK_Click(object sender, RoutedEventArgs e) { // 触发事件,不直接操作窗口 AddItemsRequested?.Invoke(this, EventArgs.Empty); } // 其余原有代码不变 } - 修改宿主窗口导航逻辑,订阅Page事件
// 替换原有直接传Uri的导航方式 private void NavigateToItemsPage() { var itemsPage = new SubPnlItems_SK(); // 订阅Page的按钮点击事件 itemsPage.AddItemsRequested += (s, args) => { this.Visibility = Visibility.Hidden; var addWindow = new PnlAddItem_SK(); addWindow.ShowDialog(); this.Visibility = Visibility.Visible; }; dockPanel_SK.NavigationService.Navigate(itemsPage); }
注意:使用该方式时不能直接传Uri导航,需要手动创建Page实例再传入导航方法,否则无法订阅实例事件。
内容的提问来源于stack exchange,提问作者Tharindu
相关产品推荐
相关产品推荐

