簡體   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