주 창의 버튼을 클릭 할 때 열려있는 사이드 윈도우가 있습니다. 이 사이드 윈도우는 메인 윈도우와는 별도의 스레드에서 생성됩니다.생성자가 객체를 소유하고있는 스레드에 없습니다.
버튼을 처음 클릭하면 모든 것이 잘 작동합니다.. 그런 다음 사이드 윈도우를 닫습니다. 이제 번 버튼을 클릭하면 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
클래스는 단지 Dispatcher
호출 내부 MonitoringWindow
클래스의 관련 방법은 크로스 스레드 호출을 처리하기 위해 랩합니다.
코드는 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)
내가 생각할 수있는 유일한 이유 것은 다음과 같습니다의 Background
속성에 바인딩 된 다른 스레드에서 만든 개체의 속성이 1
이 LineGraph
개체? 그러나 내 응용 프로그램에는 그러한 바인딩 (적어도 명시 적으로)이 없으며, 그렇다면 왜 처음에는 작동합니까?
2. Background
속성은 LineGraph
개체에 의해 소유되지 않습니다. 그러나 이것은 말이되지 않습니다.
3. 생성자가 생성중인 개체를 만든 스레드에서 실행되지 않고 있습니다. 다시 말하지만 Visual Studio 디버거에서는 "Monitoring Window Thread"스레드에서 작동하고 있다고합니다.
이 문제를 어떻게 해결할 수 있습니까?
Dispatcher
을 사용하여 배경을 설정할 수는 있지만 그 클래스와 다른 모든 UI 요소에 대한 모든 호출에는 지루하고 실제로 문제의 원인을 수정하지 않습니다.
대단히 감사합니다!
감사합니다. 'Free'()를 호출하는'Brush' 객체를 호출하는'GraphUtilities' 클래스에'static' 생성자를 추가했습니다. 문제가 해결되었습니다! 감사 :) – Brett