解決了
我的問題有點奇怪,我什至不知道為什么打開一個視窗會對我的串列系結產生任何影響,所以很難解釋,所以這里有一個視頻顯示發生了什么: https: //www.youtube .com/watch?v=bZ03l8OHEY4
我有 2 頁,起始頁和主頁。在起始頁中,用戶可以在 COM 埠上檢測到的(支持的)設備之間進行選擇。單擊設備時,程式會讀取設備并根據設備上的資料創建視圖模型串列(與 BackgroundWorker 異步),這里我還實體化并顯示加載視窗/對話框。當再次單擊設備時,程式會轉到主頁并將視圖模型串列顯示為為此設備創建的視圖串列(在 xaml 中帶有 ItemsControl)。
到目前為止一切正常。但是,如果我有 2 個設備,如果我執行 A 和 B,但執行 C 時不會出現問題。如果我不啟動加載視窗/對話框,A 和 B 都可以作業,我最后在 youtube 視頻中演示了這一點(它如果我實體化但不 .Show()) 也會中斷。
A) 和我上面說的一樣,然后我回到起始頁然后讀取并打開另一個設備。(這是我在 youtube 視頻中展示的第二件事)
B) 和我上面說的一樣,然后我閱讀并打開另一個設備而不回傳開始頁面。
C) 相反,在打開任何一個設備之前讀取兩個設備(停留在起始頁上),然后打開第一個設備,然后打開第二個設備。(這是我在 youtube 視頻中展示的第一件事)
頂部影像顯示顯示的串列與實際在計算機記憶體中的串列相同。下圖顯示了按照 B 中所述執行操作時會發生什么。正如您所見,螢屏上的串列與 LiveVisualTree 所說的串列實際不同。
執行 A/B 時,顯示的串列不會更新為其他設備的已創建視圖模型串列(仍顯示第一個設備的串列)。視圖模型串列已正確創建(是的,我檢查了兩次和三次)視圖串列沒有更新。即使我手動使用 OnPropertyChanged() 作為串列。
但是,當我做 C 時,一切都完美無缺。更新視圖串列以顯示視圖模型串列包含的內容。
我認為一些相關的代碼:
用戶點擊設備:
public static void DeviceClick(ComPortVM comPort)
{
CurrentComPort = comPort;
if (comPort.Device == null)
{
ShowReadingDeviceDialog(true);
BackgroundWorker workThread = new BackgroundWorker();
workThread.DoWork = new DoWorkEventHandler(BackgroundParameterReader_DoWork);
workThread.RunWorkerCompleted = new RunWorkerCompletedEventHandler(BackgroundNewInverter_RunWorkerCompleted);
workThread.RunWorkerAsync(new ReadParameterArgs(basic, false));
}
else
{
OpenDevice();
}
}
OBS:注釋掉 ShowReadingDeviceDialog(true) 時;問題沒有發生,一切正常
ShowReadingDeviceDialog(true);
private static void ShowReadingDeviceDialog(bool show)
{
if (ReadingDeviceDialog != null)
{
ReadingDeviceDialog.Close();
}
if (show)
{
MainWindow.instance.IsEnabled = false;
MainWindow.SetCursor(System.Windows.Input.Cursors.Wait);
ReadingDeviceDialog = new OpeningInverterDialog();
ReadingDeviceDialog.Owner = MainWindow.instance;
ReadingDeviceDialog.Show();
}
else
{
MainWindow.SetCursor(System.Windows.Input.Cursors.Arrow);
MainWindow.instance.IsEnabled = true;
}
}
OBS:當不實體化新的 ReadingDeviceDialog 時,問題不會發生并且一切正常
開放設備
private static void OpenDevice()
{
if (!isOpening)
{
isOpening = true;
if (!InfoPanels.ContainsKey(CurrentDevice))
{
InfoPanels.Add(CurrentDevice, new InfoPanelVM());
InfoPanels[CurrentDevice].SetUp(CurrentDevice);
}
MainViewModel.instance.RefreshInfoPanel();
startDelay.Interval = TimeSpan.FromMilliseconds(100);
startDelay.Start();
}
}
開始延遲滴答
private static void StartDelay_Tick(object sender, EventArgs e)
{
MainWindow.OpenPage("MainPage");
if (!paramTabBars.ContainsKey(CurrentDevice))
{
MainPage.ClearFrame();
paramTabBars.Add(CurrentDevice, new ParamTabBarVM());
ParamTabBar.SetUp(CurrentDevice);
}
else
{
ParamTabBar.OpenTab("");
}
startDelay.Stop();
isOpening = false;
ShowReadDeviceDialog(false);
MainViewModel.instance.RefreshParamTabBtns();
}
It's the ParamBarTab that contains the list that causes problems, called ParamTabBtns. Using MainViewModel.instance.RefreshParamTabBtns(); simply uses OnPropertyChanged(ParamTabBtns) for the currently selected Device, this fixed a similiar problem i had with the view list not updating to fit view model list. However this fix does not work now when i instantiate a loading dialog window.
Since the binding had worked all the time before i started instantiating a loading dialog i do not think the problem is in XAML, so i won't bother posting that to.
I know this question maybe weridly asked, but since i have no clue on what going on i don't really know what else information i should provide. I'm mostly just hoping for someone giving me ideas as what kind of thing that might possibly be the thing i should try to find, but right now i'm totally blind.
Edit: I'm starting to suspect it's a bug in WPF and not on my side? LiveVisualTree the DataContext gives me the right list, but that list is not shown on screen. Screen cap with green arrows is when everything works, with red arrows is when i did like in A. The list to the side that says 15 in length is the list that is supposed to be shown in the application, yet it isnt. Isn't LiveVisualTree supposed to show me the binding? If the binding works in LiveVisualTree isn't it supposed to work in the application too? Isn't that what LiveVisualTree is used for? Debugging? So shouldnt the bindings in LiveVisualTree reflect the actual bindings happening inside the application?
Edit 2: I tried BindingOperations.EnableCollectionSynchronization following http://10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux However, this had no impact on anything. So it probably isn't threading related either? And it doesnt make sense that it is threading related anyway, since i can change the collection as i please when the dialog window has not been intantiated in scenario A and B. And again, the dialog window has noting the do with the collection (no references, no method calls, no nothing) LiveVisualTree
EDIT 3, SOLUTION: Apparently when using
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
WPF creates a new instance of the datacontext, in the constructor of my MainViewModel i had static reference to itself. But when i instantiated a new window that reference got pointed to the newly created datacontext instead, which destroyed the bindings. To fix this i removed the code from above from all xaml files that had it and instead put this in the construction (code behind) DataContext = MainViewModel.instance;
uj5u.com熱心網友回復:
顯然在使用時
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
WPF 創建資料背景關系的新實體,在我的 MainViewModel 的建構式中,我對自身有靜態參考。但是當我實體化一個新視窗時,該參考被指向新創建的資料背景關系,這破壞了系結。為了解決這個問題,我從所有擁有它的 xaml 檔案中洗掉了上面的代碼,而是把它放在構造中(代碼后面):
DataContext = MainViewModel.instance;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/415532.html
標籤:
