The calling thread cannot access this object because a different thread owns it.How do i edit the image?
i know there's a lot of these type of questions. i wanted to post so that i can share my specific prob because im getting frustrated.
im running a thread which query path from db and put it in the image element.problem is, i created the image in xaml so when i run this thread it throws the cannot access this object error which it cant access the image element.
then how do i set it without using xaml??here's my code snippet:
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();
}
how would i access image1
then? if i create a new one within the thread,i will have to put as child of a panel,an then im gonna get an error which it cant access the panel.
any way around this?glad if someone can write an example based on my snippet.
edited with still no success and producing the same error:
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();
}
}
As Jon Skeet said, you can use Dispatcher.Invoke
to assign the image, but it's not enough, because the BitmapImage
has been created on another thread. To be able to use it on the UI thread, you need to Freeze
it before:
logo.Freeze();
Action action = delegate { image1.Source = logo; };
image1.Dispatcher.Invoke(action);
You use the Dispatcher
associated with the control you want to update:
Action action = delegate { image1.Source = logo; };
image1.Dispatcher.Invoke(action);
Note that using Thread.Sleep
like this to perform animation is unlikely to give a very good experience... especially as the display thread then has to fetch the URI in order to display the image. It's not going to be very smooth.
i think this is because you didnt marshal the call to the UI thread. you can do something line this:
save the context in the constructor,
// 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);
by the way, its a good practice to use using statements with the SqlConnection
and SqlDataReader
. as in:
using (SqlConnection conn = new SqlConnection("conn string here"))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
// db access code
}
}
精彩评论