繁体   English   中英

WPF Frame.Navigate 触发多个事件

[英]WPF Frame.Navigate triggering multiple events

我是 WPF 和 C# 的新手。我的主 window 上有一个框架组件,旁边有 4 个按钮,可以导航到框架中的不同视图。 在一个视图中有一个 DataGrid,它有一个 SelectionChanged 事件,该事件调用 SQL 来获取记录的数据库,然后使用其数据填充自定义对象列表(这些与 DataGrid 上的选定项目相关)。 无论如何,我遇到的问题是,对于 DataGrid 上的单个选择更改(鼠标单击),有时会同时触发对 SelectionChanged 事件的多次调用(2 次或 3 次)。

主 window 上的导航按钮点击事件都是这样的:

    private void btn_MyDesk_Click(object sender, RoutedEventArgs e)
    {
        MainFrame.Navigate(new Uri("/Views/MyDeskView.xaml", UriKind.Relative));
    }

    private void btn_AllOrders_Click(object sender, RoutedEventArgs e)
    {
        MainFrame.Navigate(new Uri("/Views/AllOrdersView.xaml", UriKind.Relative));
    }

经过一些实验后,我发现该错误仅在使用 DataGrid 将视图从视图更改为其他视图,然后再更改回该视图(但并非总是如此)后才会发生。 当错误出现时,调用次数通常对应于我切换视图的次数。 此外,如果将程序单独放置一两分钟,该错误就会消失。 这让我怀疑 DataGrid 视图的多个实例像 memory 中的幽灵一样挥之不去,并重复事件调用,直到它们被垃圾收集器清除。

每次切换视图时我应该清理一些东西,还是我找错地方了?

预先感谢您的任何帮助。

编辑:作为对@Peter Moore 的回答,我订阅了视图 XAML 中 DataGrid 声明中的事件:SelectionChanged="dtg_MyDeskOrderGrid_SelectionChanged"

编辑:这是在数据网格中选择更改时发生的序列。 它包括几个 UI 更改,同时检索新选择的 SQL 条记录并将其显示在第二个 DataGrid (dtg_MyDeskOrderItems) 上。 当调用 SQL 时,相关控件被禁用,一个半透明面板 (bdr_DGLoadingPanel) 被移动到屏幕上以覆盖它们并显示加载 animation。当工作完成后,工作区被重新启用并且加载面板移出屏幕。 焦点也返回到主“订单”Datagrid。

dtg_MyDeskOrderGrid:这是显示所有“订单”的主要数据网格

dtg_MyDeskOrderItems:这是一个辅助 DataGrid,已更新以显示所选订单中的所有“项目”。

    private void dtg_MyDeskOrderGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        CurrSelectedOrder = (Order_class)dtg_MyDeskOrderGrid.SelectedItem;
        if (CurrSelectedOrder.ItemList == null) 
        {
            if (NowWorking == false)
            {
                NowWorking = true;
                bdr_DGLoadingPanel.Margin = new Thickness(2);
                dtg_MyDeskOrderGrid.IsEnabled = false;
                bdr_FilterPanel.IsEnabled = false;
                bdr_DGLoadingPanel.Focus();
                img_LoadingCircle.RenderTransform = rt;
                img_LoadingCircle.RenderTransformOrigin = new Point(0.5, 0.5);
                da.RepeatBehavior = RepeatBehavior.Forever;
                rt.BeginAnimation(RotateTransform.AngleProperty, da);
                bdr_DGLoadingPanel.UpdateLayout();
                worker.RunWorkerAsync();
            }
        }
        else
        {
            dtg_MyDeskOrderItems.ItemsSource = null;
            dtg_MyDeskOrderItems.ItemsSource = CurrSelectedOrder.ItemList;
            dtg_MyDeskOrderItems.Items.Refresh();
        }
    }

    private void worker_DoWork(object? sender, DoWorkEventArgs e)
    {
        DatabaseConnection DBConn9 = new DatabaseConnection();
        DBConn9.FillOrderItems(CurrSelectedOrder);
    }

    private void worker_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
    {
        this.Dispatcher.Invoke(() =>
        {
            dtg_MyDeskOrderItems.ItemsSource = null;
            dtg_MyDeskOrderItems.ItemsSource = CurrSelectedOrder.ItemList;
            dtg_MyDeskOrderItems.Items.Refresh();
            bdr_DGLoadingPanel.Margin = new Thickness(1000, 2, 2, 2);
            rt.BeginAnimation(RotateTransform.AngleProperty, null);
            dtg_MyDeskOrderGrid.IsEnabled = true;
            bdr_FilterPanel.IsEnabled = true;
            // The following work-around and accompanying GetDataGridCell function were used to give keyboard focus back to the datagrid to make navigation with arrow keys work again.
            // It appears keyboard focus is not returned to the Datagrid cells when using the Datagrid.focus() method.
            Keyboard.Focus(GetDataGridCell(dtg_MyDeskOrderGrid.SelectedCells[0]));
            NowWorking = false;
        });
    }

编辑...按照评论者的建议,我能够通过取消订阅包含 DataGrid 的视图的 Unloaded 事件中的事件来修复错误:

private void uct_MyDeskView_Unloaded(object sender, RoutedEventArgs e)
    {
        dtg_MyDeskOrderGrid.SelectionChanged -= dtg_MyDeskOrderGrid_SelectionChanged;
    }

但是,我无法使用准系统测试项目重现该错误。

原始项目中的 UI 非常繁重,所以我想知道它是否不是旧视图和事件在 memory 中挥之不去,因为这似乎符合错误和修复的行为(仅在我导航离开和返回时发生,导致新的要创建的视图,多个事件触发器对应于我导航离开的次数,然后最终在一两分钟后错误自行消失)。

我不会将此作为最终解决方案,而是了解如何重用我的视图实例(如 Bionic 所建议的)而不是重新创建它们。 这样做的原因是,如果 SelectionChanged 事件从旧视图实例中获取多个触发器,那么其他事件很可能会遇到相同的错误。 这会很糟糕。

@BionicCode 如果您还在附近,能否将您的初始评论重新发布为解决方案,以便我将其标记为已回答?

感谢大家的帮助和教育。 ^_^

按照评论者的建议,我最初能够通过取消订阅包含 DataGrid 的视图的 Unloaded 事件中的事件来修复错误:

private void uct_MyDeskView_Unloaded(object sender, RoutedEventArgs e)
    {
        dtg_MyDeskOrderGrid.SelectionChanged -= dtg_MyDeskOrderGrid_SelectionChanged;
    }

然而,由于这个解决方案只断开了一个事件,并没有解决旧视图在后台挥之不去并在被清理之前触发事件的根本问题,我最终使用了以下代码,它只在 memory 中保留了我的视图的一个实例并重用它。

private MyDeskView? currMyDeskView = null;

private void btn_MyDesk_Click(object sender, RoutedEventArgs e)
    {
        if (currMyDeskView == null)
        {
            currMyDeskView = new MyDeskView();
        }
        MainFrame.Navigate(currMyDeskView);
    }

感谢所有帮助我克服这个错误的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM