为什么我不能在以下代码中创建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);
}
);
答案 0 :(得分:16)
以下代码可能会帮助您解决从另一个线程更新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
}
}
答案 1 :(得分:7)
使用WPF时要注意,如果在一个线程中创建UI对象,则无法从另一个线程访问它。您的UI对象应该(通常)创建UI线程,然后您需要UI线程以后访问它们。没有其他线程可以访问在UI线程上创建的对象。
如果您需要从另一个线程访问UI对象,则需要UI线程Dispatcher,然后您可以使用它来调用UI线程上的调用。
我花了很多时间来解决类似的问题 - 相信我..查看this question - 它给了我很多关于这个主题的有用信息。
答案 2 :(得分:3)
您可以在反射器中查看此类。 cb.Freeze()中会出现异常。在
CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
案例构造函数做了类似这样的事情:
this.this.Source = source;
因此源不是在当前线程中创建的,因此异常将会增加。 在
new WriteableBitmap(bf)
case,构造函数与bf对象同步,并在当前线程中创建新源,因此,不会出现异常。 如果您对In Depth详细信息感兴趣,可以随时使用Reflector反映基础库:)
答案 3 :(得分:2)
我遇到了同样的问题并通过使用其调度程序(可以通过UIElement
访问)在UI线程中创建Application.Current.Dispatcher
来解决问题。
在:
public static UIElement CreateUIElement()
{
UIElement element = new UIElement();
//Initialized the UIElement here
return element;
}
此代码导致XamlParseException,因为它是在与UI线程不同的线程中调用的。
我的工作解决方案:
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
祝你好运