亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么 C# WPF 按鈕綁定命令在使用簡單注入器后不會更改視圖?

為什么 C# WPF 按鈕綁定命令在使用簡單注入器后不會更改視圖?

C#
烙印99 2022-11-13 13:55:15
我正在使用以下文章作為入門代碼: 在 WPF MVVM簡單注入器 WPF 集成中的視圖之間導航目標:嘗試使用按鈕綁定命令和簡單注入器以 WPF 形式從視圖 1 轉到視圖 2,以將依賴項注入視圖。注意:這些依賴項是保存來自外部來源的數據的存儲庫。問題:使用 Simple Injector 將依賴項注入到我的 MainWindow 和 MainWindowViewModel 后,我的按鈕不再更改我的當前視圖(到我的另一個視圖)。當使用 Visual Studio 并使用斷點進行調試時,代碼似乎永遠停留在CanExecuteRelayCommand.cs 函數中的循環中(請參閱在 WPF MVVM 中的視圖之間導航),其中某些東西一遍又一遍地調用它。我無法對CanExecute函數進行更多調試,因為有很多代碼被傳遞(來自 DLL 等)。當不使用斷點時,它就好像我的按鈕什么也沒做一樣。我在輸出窗口中沒有看到按鈕錯誤,也沒有拋出異常。命令綁定有效,因為我可以看到OnGo2Screen在調試時調用了 MainWindowViewModel.cs 中的函數。調用后OnGo2Screen,它按預期移動代碼,直到卡在CanExecute.我試過的我檢查了我的 MainWindow 的數據上下文,我可以看到它具有所有正確的功能。我為“在 WPF MVVM 中的視圖之間導航”一文創建了一個單獨的項目,我能夠很好地更改視圖。但是每當我嘗試使用 Simple Injector 時,我的按鈕就會壞掉。我注意到,當不使用 Simple Injector 時,代碼從CanExecute函數移動到CanExecuteChangedEventHandler 并執行刪除和添加修改器,然后按預期更改視圖。但是,當使用 Simple Injector 時,它不會這樣做。我使用我的 App.xaml.cs 作為啟動程序的代碼,其中我的 App.xaml 具有“頁面”的構建操作。SimulationCaseView 是視圖 1(默認起始視圖)。StreamsView 是視圖 2(只是另一個視圖)。UserControl3 是視圖 3(只是另一個視圖)。下面是我的代碼。請參閱為任何剩余代碼提供的兩個鏈接,因為我的很多功能都基于此。
查看完整描述

2 回答

?
一只斗牛犬

TA貢獻1784條經驗 獲得超2個贊

如何解決?

在更新命令狀態后調用此方法:

CommandManager.InvalidateRequerySuggested();

為什么不更新?

命令僅在這些一般事件發生時更新:

  • KeyUp

  • MouseUp

  • GotKeyboardFocus

  • LostKeyboardFocus

有關詳細信息,請參閱此源代碼:CommandDevice.cs

對于其他控件,它有更多的事件需要刷新:

  • 長按時重復增加RepeatButton

  • DataGrid...

  • SinglePageViewer...

您可以雙擊此鏈接CommandManager.InvalidateRequerySuggested()的方法查看其他刷新命令狀態的事件。

因此,如果您的更新不在這些事件中發生,您的命令狀態將不會更新。

其他信息

您說在使用 Visual Studio 并使用斷點進行調試時,代碼似乎在CanExecuteRelayCommand.cs 的函數中永遠卡在一個循環中。

這不是 for 的循環CanExecute,而是活動窗口在應用程序和 Visual Studio 之間切換時的GotKeyboardFocusand事件。LostKeyboardFocus


查看完整回答
反對 回復 2022-11-13
?
叮當貓咪

TA貢獻1776條經驗 獲得超12個贊

簡答

問題在于Lifestyle您的 ViewModel 必須設置為 aSingleton而不是 default Transient。


    private static Container Bootstrap()

    {

        // Create the container as usual.

        var container = new Container();


        // Register your types, for instance:



        // Register your windows and view models:

        //container.Register<MainWindow>(Lifestyle.Singleton); //not needed

        container.Register<MainWindowViewModel>(Lifestyle.Singleton);


        container.Verify();


        return container;

    }

然后你可以通過簡單的方式啟動應用程序


    private static void RunApplication(Container container)

    {

        try

        {

            var mainWindow = container.GetInstance<MainWindow>();

            var app = new App();

            app.InitializeComponent();

            app.Run(mainWindow);

        }

        catch (Exception ex)

        {

            //Log the exception and exit

            Debug.WriteLine(ex.Message);

        }

    }

完整代碼在github 上。


長答案 - TL; DR

當您調用container.Verifyin 時,Bootstrap您將創建一個實例MainWindowViewModel來驗證其實例化,并創建另一個實例來驗證MainWindow類。


順便說一句,您可以通過不驗證容器來解決您的問題!


所以第二個解決方案是


        //container.Register<MainWindow>(); // => Lifestyle.Transient;

        container.Register<MainWindowViewModel>(); // => Lifestyle.Transient;


        //container.Verify();

現在,請注意您在c.tor中有Mediator訂閱。MainWindowViewModel


    public static void Subscribe(string token, Action<object> callback)

    {

        if (!pl_dict.ContainsKey(token))

        {

            var list = new List<Action<object>>();

            list.Add(callback);

            pl_dict.Add(token, list);

        }

        else

        {

            bool found = false;

            //foreach (var item in pl_dict[token])

            //    if (item.Method.ToString() == callback.Method.ToString())

            //        found = true;

            if (!found)

                pl_dict[token].Add(callback);

        }

    }

foreach循環——我只在上面評論過(它是解決你的問題的第三個替代選項) ——會讓你跳過對第二個正確的 ViewModel 方法的調用,并會讓你留下第一個錯誤的方法(記住Bootstrap驗證創建了它兩次)。如果你想要第四種替代解決方案,使用中介者模式IComponent的經典界面


public interface IComponent

{

     void OnGo1Screen(object obj);

     void OnGo2Screen(object obj);

}

public class MainWindowViewModel : BaseViewModel, IComponent

您還可以將訂閱移出 c.tor


  public MainWindowViewModel()

  {

     // Add available pages and set page

     PageViewModels.Add(new UserControl1ViewModel());

     PageViewModels.Add(new UserControl2ViewModel());


     CurrentPageViewModel = PageViewModels[0];


     //Mediator.Subscribe("GoTo1Screen", OnGo1Screen);

     //Mediator.Subscribe("GoTo2Screen", OnGo2Screen);

  }

進入你的Program:


            var context = mainWindow.DataContext as IComponent;

            Mediator.Subscribe("GoTo1Screen", context.OnGo1Screen);

            Mediator.Subscribe("GoTo2Screen", context.OnGo2Screen);


查看完整回答
反對 回復 2022-11-13
  • 2 回答
  • 0 關注
  • 166 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號