web-dev-qa-db-ja.com

別のスレッドが所有しているため、呼び出しスレッドはこのオブジェクトにアクセスできません

次のコードでCroppedBitmapを作成できないのはなぜですか?例外が発生しました:

別のスレッドが所有しているため、呼び出しスレッドはこのオブジェクトにアクセスできません。

コードを次のように変更した場合

_CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5));
_

例外はなくなった?どうして ?

コード1、cb.Freeze()での例外:

_public MainWindow()
{
    InitializeComponent();

    ThreadPool.QueueUserWorkItem((o) =>
        {
            //load a large image file
            var bf = BitmapFrame.Create(
                new Uri("D:\\1172735642.jpg"),
                BitmapCreateOptions.None,
                BitmapCacheOption.None);
            bf.Freeze();
            Dispatcher.BeginInvoke(
                new Action(() =>
                    {
                        CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
                        cb.Freeze();
                        //set Image's source to cb....
                    }), 
                    DispatcherPriority.ApplicationIdle);
         }
    );
}
_

コード2、動作:

_    ThreadPool.QueueUserWorkItem((o) =>
    {
        var bf = BitmapFrame.Create(
                new Uri("D:\\1172740755.jpg"),
                BitmapCreateOptions.None,
                //BitmapCreateOptions.DelayCreation,
                BitmapCacheOption.None);
        bf.Freeze();
        var wb = new WriteableBitmap(bf);
        wb.Freeze();
        this.Dispatcher.Invoke(
            new Action(() =>
            {
                var r = new Int32Rect(1, 1, 5, 5);
                CroppedBitmap cb = new CroppedBitmap(wb, r);
                cb.Freeze();
                //set Image's source to cb....
                Image.Source = cb;
            }),
            DispatcherPriority.ApplicationIdle);
    }
);
_

コード3、WritableBitmapなしで動作:

_ThreadPool.QueueUserWorkItem((o) =>
    {
        var bf = BitmapFrame.Create(
                new Uri("D:\\1172735642.jpg"),
                BitmapCreateOptions.None,
                //BitmapCreateOptions.DelayCreation,
                BitmapCacheOption.None);
        bf.Freeze();
        var bf2 = BitmapFrame.Create(bf);
        bf2.Freeze();

        this.Dispatcher.Invoke(
            new Action(() =>
            {
                var r = new Int32Rect(1, 1, 5, 5);
                BitmapSource cb = new CroppedBitmap(bf2, r);
                cb.Freeze();
                //set Image's source to cb....
                Image.Source = cb;
            }),
            DispatcherPriority.ApplicationIdle);
    }
);
_
20
zunyite

このクラスをリフレクターで確認できます。 cb.Freeze()で例外が発生します。に

CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));

ケースコンストラクタは次のようなことをしました:

this.this.Source = source;

そのため、ソースは現在のスレッドで作成されなかったため、例外が発生します。に

new WriteableBitmap(bf)

場合、コンストラクターはbfオブジェクトと同期し、現在のスレッドで新しいソースが作成されるため、例外は発生しません。 In Depthの詳細に興味がある場合は、常にReflectorを使用してベースライブラリを反映できます。

3
Andrew

次のコードは、別のスレッドからgui要素を更新する問題の解決に役立つ場合があります。

モジュールレベル

delegate void updateCallback(string tekst);

これはあなたの要素を更新する方法です:

private void UpdateElement(string tekst)
{
    if (element.Dispatcher.CheckAccess() == false)
    {
        updateCallback uCallBack = new updateCallback(UpdateElement);
        this.Dispatcher.Invoke(uCallBack, tekst);
    }
    else
    { 
//update your element here
    }
 }
16
Terry

WPFを使用する場合、1つのスレッドでUIオブジェクトを作成すると、別のスレッドからアクセスできないことに注意してください。 UIオブジェクトは(通常)UIスレッドで作成する必要があり、後でそれらにアクセスするにはUIスレッドが必要です。他のスレッドは、UIスレッドで作成されたオブジェクトにアクセスできません。

別のスレッドからUIオブジェクトにアクセスする必要がある場合は、UIスレッド Dispatcher が必要です。これを使用して、UIスレッドで呼び出しを呼び出すことができます。

私はこれに似た問題のフラストレーションに何時間も費やしてきました-信じてください。チェックしてください この質問 -それは私に多くの有用な情報を与えました件名。

7
stiank81

私は同じ問題を抱えており、そのディスパッチャ(Application.Current.Dispatcherからアクセスできる)を使用してUIスレッドにUIElementを作成することで問題を修正しました。

前:

public static UIElement CreateUIElement()
{
    UIElement element = new UIElement();
    //Initialized the UIElement here
    return element;
}

このコードは、UIスレッドとは異なるスレッドで呼び出されたため、XamlParseExceptionを引き起こしました。

私の作業ソリューション:

public static UIElement CreateUIElement()
{
    UIElement element = null;
    Application.Current.Dispatcher.Invoke(
       System.Windows.Threading.DispatcherPriority.Normal, new Action(
          delegate()
          {
              element = new UIElement();
              // Initialize your UIElement here
          }));
    return element;
}

ディスパッチャーの詳細については、こちらをご覧ください http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher

幸運を

2
Bahamut