调用线程无法访问此对象,因为不同的线程拥有它。如何编辑图像?

我知道有很多这类问题。 我想发帖,以便我可以分享我的具体问题因为我感到沮丧。

我正在运行一个从db查询路径并将其放入图像元素的线程。问题是,我在xaml中创建了图像,所以当我运行这个线程时,它会抛出无法访问此对象的错误,它无法访问图像元素。

那我怎么设置它而不使用xaml ??这里是我的代码片段:

public partial class Window1 : Window { Thread Frame1; public Window1() { InitializeComponent(); intializeDb(); #region start frame 1 thread Frame1 = new Thread(frame1); Frame1.SetApartmentState(ApartmentState.STA); Frame1.IsBackground = true; Frame1.Start(); #endregion } public void frame1() { string k; command.CommandText = "SELECT * FROM imageframe1"; sqlConn.Open(); Reader = command.ExecuteReader(); while (Reader.Read()) { BitmapImage logo = new BitmapImage(); logo.BeginInit(); k = (string)(Reader.GetValue(1)); logo.UriSource = new Uri(k); logo.EndInit(); image1.Source = logo; //THROWS THE ERROR HERE.IT CANT ACCESS image1 Thread.Sleep(1000); } sqlConn.Close(); Reader.Close(); } 

那我怎么访问image1呢? 如果我在线程中创建一个新的,我将不得不作为一个面板的孩子,然后我将得到一个它无法访问面板的错误。

这有什么办法吗?很高兴如果有人可以根据我的片段写一个例子。

编辑仍然没有成功,并产生相同的错误:

 public partial class Window1 : Window { public readonly SynchronizationContext mySynchronizationContext; public Window1() { InitializeComponent(); mySynchronizationContext = SynchronizationContext.Current; Frame1 = new Thread(frame1); Frame1.SetApartmentState(ApartmentState.STA); Frame1.IsBackground = true; Frame1.Start(); } public void frame1() { string k; command.CommandText = "SELECT * FROM imageframe1"; sqlConn.Open(); Reader = command.ExecuteReader(); while (Reader.Read()) { BitmapImage logo = new BitmapImage(); logo.BeginInit(); k = (string)(Reader.GetValue(1)); logo.UriSource = new Uri(k); logo.EndInit(); SendOrPostCallback callback = _ => { image1.Source = logo; }; mySynchronizationContext.Send(callback, null); //image1.Source = logo; Thread.Sleep(1000); } sqlConn.Close(); Reader.Close(); } } 

正如Jon Skeet所说,你可以使用Dispatcher.Invoke来分配图像,但这还不够,因为BitmapImage是在另一个线程上创建的。 为了能够在UI线程上使用它,您需要在以下之前Freeze它:

 logo.Freeze(); Action action = delegate { image1.Source = logo; }; image1.Dispatcher.Invoke(action); 

您使用与要更新的控件关联的Dispatcher

 Action action = delegate { image1.Source = logo; }; image1.Dispatcher.Invoke(action); 

请注意,使用这样的Thread.Sleep来执行动画不太可能提供非常好的体验…尤其是当显示线程必须获取URI以显示图像时。 它不会很顺利。

我认为这是因为你没有封送对UI线程的调用。 你可以做一些事情:

在构造函数中保存上下文,

 // this is a class member variable public readonly SynchronizationContext mySynchronizationContext; // in ctor MySynchronizationContext = SynchronizationContext.Current; // in your method , to set the image: SendOrPostCallback callback = _=> { image1.Source = logo; }; mySynchronizationContext.Send(callback,null); 

顺便说一下,使用带有SqlConnectionSqlDataReader语句是一个很好的做法。 如:

 using (SqlConnection conn = new SqlConnection("conn string here")) { using (SqlDataReader reader = cmd.ExecuteReader()) { // db access code } }