我有一個側窗在點擊主窗口上的按鈕時打開。這個側窗是在與主窗口分開的線程上創建的。構造函數不在擁有該對象的線程上
當我點擊按鈕第一次,一切運行良好。然後關閉側窗。現在當我點擊按鈕第二次,它會拋出InvalidOperationException
。
當側窗關閉時,它和它所運行的線程被丟棄,每次打開時,都會創建一個全新的線程,創建一個全新的窗口。在窗口的最低子元素的構造函數中引發異常(即,在構建窗口時第一次訪問UI對象)。
這是發生了什麼事。按鈕的處理程序點擊:
public partial class MainWindow : Window
{
private void OnVariableMonitoringButtonClick(object sender, RoutedEventArgs e)
{
if (monitoringWindow == null)
{
Cursor = Cursors.Wait;
monitoringWindow = new MonitoringWindowWrapper();
monitoringWindow.Loaded += OnMonitoringWindowLoaded;
monitoringWindow.Closed += OnMonitoringWindowClosed;
monitoringWindow.Start(); // <---
}
else
{
monitoringWindow.Activate();
}
e.Handled = true;
}
void OnMonitoringWindowLoaded(object sender, EventArgs e)
{
Dispatcher.Invoke(new Action(() => Cursor = Cursors.Arrow));
}
void OnMonitoringWindowClosed(object sender, EventArgs e)
{
monitoringWindow = null;
Dispatcher.Invoke(new Action(() => Cursor = Cursors.Arrow));
}
}
的MonitoringWindowWrapper
類只是包裝了MonitoringWindow
類的內部Dispatcher
調用相關的方法來處理跨線程調用。
的代碼進入MonitoringWindowWrapper.Start()
方法:
partial class MonitoringWindowWrapper
{
public void Start()
{
// Construct the window in a parallel thread
Thread windowThread = new Thread(LoadMonitoringWindow);
windowThread.Name = "Monitoring Window Thread";
windowThread.IsBackground = true;
windowThread.SetApartmentState(ApartmentState.STA);
windowThread.Start(); // <---
}
private void LoadMonitoringWindow()
{
try
{
// Construct and set up the window
monitoringWindow = new MonitoringWindow(); // <---
monitoringWindow.Loaded += OnMonitoringWindowLoaded;
monitoringWindow.Closed += OnMonitoringWindowClosed;
monitoringWindow.Show();
// Start window message pump on this thread
System.Windows.Threading.Dispatcher.Run();
}
catch (Exception e)
{
// Catch any exceptions in this window to save the application from crashing
ErrorMessasgeBox.Show(e.Message);
if (Closed != null) Closed(this, new EventArgs());
}
}
}
的代碼然後進入MonitoringWindow.MonitoringWindow()
構造和過濾下來的窗口我最低的子元素:
public partial class MonitoringWindow : Window
{
public MonitoringWindow()
{
InitializeComponent(); // <---
// ...
}
}
一路下來到:
public partial class LineGraph : UserControl, IGraph, ISubGraph
{
public LineGraph()
{
InitializeComponent();
Brush b = GraphUtilities.BackgroundGradient;
Background = b; // EXCEPTION THROWN AT THIS LINE
BorderBrush = GraphUtilities.Border;
}
}
異常調用堆棧可能會這樣我見識到哪裏拋出異常:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The calling thread cannot access this object because a different thread owns it.
Source=WindowsBase
StackTrace:
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.Freezable.ReadPreamble()
at System.Windows.Media.GradientStopCollection.OnInheritanceContextChangedCore(EventArgs args)
at System.Windows.DependencyObject.OnInheritanceContextChanged(EventArgs args)
at System.Windows.DependencyObject.OnInheritanceContextChanged(EventArgs args)
at System.Windows.Freezable.AddInheritanceContext(DependencyObject context, DependencyProperty property)
at System.Windows.DependencyObject.ProvideSelfAsInheritanceContext(DependencyObject doValue, DependencyProperty dp)
at System.Windows.DependencyObject.ProvideSelfAsInheritanceContext(Object value, DependencyProperty dp)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at System.Windows.Controls.Control.set_Background(Brush value)
at Graphing.LineGraph..ctor() in z:\Documents\Projects\Software\Serial\SerialWindows\Graphing\LineGraph\LineGraph.xaml.cs:line 28
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
,我能想到的唯一原因如下:
1.有上綁定到的Background
財產另一個線程創建的對象的屬性這個LineGraph
對象?但是,在我的應用程序中沒有任何這樣的綁定(至少是明確的),如果是這樣的話,爲什麼它第一次工作?
2. Background
屬性不知何故不屬於LineGraph
對象?但這沒有意義。
3.構造函數在某種程度上沒有在創建它正在構造的對象的線程上執行?這再次沒有意義,並且Visual Studio調試器說它正在「監視窗口線程」線程上運行。
我該如何解決這個問題?
我可以使用Dispatcher
來設置背景,但對於該類和所有其他UI元素的所有調用來說,這是非常單調乏味的,而且它並沒有真正解決問題的原因。
非常感謝!
謝謝!我向'GraphUtilities'類添加了一個'static'構造函數,它在所有暴露的'Brush'對象上調用'Freeze()'。這解決了問題!謝謝 :) – Brett 2012-07-11 20:54:52