メインウィンドウのボタンをクリックすると開くサイドウィンドウがあります。このサイド ウィンドウは、メイン ウィンドウとは別のスレッドで作成されます。
初めてボタンをクリックすると、すべて正常に動作します。次に、サイドウィンドウを閉じます。ボタンをもう一度クリックすると、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.このオブジェクトのプロパティに
バインドされている別のスレッドで作成されたオブジェクトのプロパティがありますか? しかし、私のアプリケーションには (少なくとも明示的には) そのようなバインディングはありません。
2.プロパティが何らかの形でオブジェクトによって所有されていない? しかし、これは意味がありません。
3. コンストラクターが、構築中のオブジェクトを作成したスレッドで何らかの形で実行されていませんか? これも意味がなく、Visual Studio デバッガーは、"Monitoring Window Thread" スレッドで動作していると表示します。 Background
LineGraph
Background
LineGraph
この問題を解決するにはどうすればよいですか?
を使用しDispatcher
て背景を設定することもできますが、そのクラスやその他すべての UI 要素へのすべての呼び出しが非常に面倒であり、問題の原因を実際に修正することにはなりません。
どうもありがとうございました!