次のコードで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);
}
);
_
このクラスをリフレクターで確認できます。 cb.Freeze()で例外が発生します。に
CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
ケースコンストラクタは次のようなことをしました:
this.this.Source = source;
そのため、ソースは現在のスレッドで作成されなかったため、例外が発生します。に
new WriteableBitmap(bf)
場合、コンストラクターはbfオブジェクトと同期し、現在のスレッドで新しいソースが作成されるため、例外は発生しません。 In Depthの詳細に興味がある場合は、常にReflectorを使用してベースライブラリを反映できます。
次のコードは、別のスレッドから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
}
}
WPFを使用する場合、1つのスレッドでUIオブジェクトを作成すると、別のスレッドからアクセスできないことに注意してください。 UIオブジェクトは(通常)UIスレッドで作成する必要があり、後でそれらにアクセスするにはUIスレッドが必要です。他のスレッドは、UIスレッドで作成されたオブジェクトにアクセスできません。
別のスレッドからUIオブジェクトにアクセスする必要がある場合は、UIスレッド Dispatcher が必要です。これを使用して、UIスレッドで呼び出しを呼び出すことができます。
私はこれに似た問題のフラストレーションに何時間も費やしてきました-信じてください。チェックしてください この質問 -それは私に多くの有用な情報を与えました件名。
私は同じ問題を抱えており、そのディスパッチャ(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
幸運を