0

メインウィンドウのボタンをクリックすると開くサイドウィンドウがあります。このサイド ウィンドウは、メイン ウィンドウとは別のスレッドで作成されます。

初めてボタンをクリックすると、すべて正常に動作します。次に、サイドウィンドウを閉じます。ボタンをもう一度クリックする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" スレッドで動作していると表示します。 BackgroundLineGraph
BackgroundLineGraph

この問題を解決するにはどうすればよいですか?

を使用しDispatcherて背景を設定することもできますが、そのクラスやその他すべての UI 要素へのすべての呼び出しが非常に面倒であり、問​​題の原因を実際に修正することにはなりません。

どうもありがとうございました!

4

2 に答える 2

2

犯人はだと思いますが、あなたはクラスGraphUtilities.BackgroundGradientをリストしていません。GraphUtilitiesブラシはフリーズ可能なオブジェクトです。

MSDNのFreezableObjectsの概要から:

凍結されたFreezableはスレッド間で共有することもできますが、凍結されていないFreezableは共有できません。

したがって、初めて実行するとき、そのブラシは監視ウィンドウスレッドに関連付けられています。次にそのウィンドウを開くと、それは新しいスレッドです。他のスレッドから使​​用する場合は、ブラシでFreezeメソッドを呼び出す必要があります。

于 2012-07-11T04:21:31.473 に答える
1

すべての UI リソースが作成され、単一のスレッド (UI スレッド) によって所有されることが、WPF の前提条件です。多くのことが、これがそうなるという仮定の妥当性に依存します。これに従わない場合、すべての賭けは無効になります。

バックグラウンド スレッドで使用するために、バックグラウンド スレッドで待機インジケーター UIを作成する必要はありません。大規模なアプリケーションは、すべての UI をメイン スレッドで作成します。長時間実行されるアクティビティは、バックグラウンド スレッドで発生します。時が来たら、UI を更新するのに十分な時間だけ UI スレッドにマーシャルを制御します。

先に進む前に、これを注意深く読むことをお勧めします。


それで、あなたはあなたが望んでいた答えを得ました。何かができるという事実は、それを良い考えにするわけではありません。ソフトウェア設計では、賢いことと賢いことはめったに同じではありません。

于 2012-07-10T05:36:30.173 に答える