2

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();

    }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
Psychocryo
  • 2,103
  • 8
  • 26
  • 33

3 Answers3

17

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);
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • You really saved my life! thnx a bunch! i've never come across Freeze before.im going to read it to understanda whats going on.thnx again. – Psychocryo May 11 '11 at 10:43
  • Wow!!!! Really, Application.Current.Dispatcher.Invoke(()=>{...}); not enough! Thanks a lot! – zzfima Apr 27 '22 at 12:16
3

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • just like that??where should i put it?please help..yep,i know it wont be smooth.thnx.but im going one by one here.later i'll want to learn to do the proper animation. – Psychocryo May 11 '11 at 08:26
  • now i get this error "Exception has been thrown by the target of an invocation." – Psychocryo May 11 '11 at 08:28
  • @Psychocryo: The exception should be specified as a nested exception - have a look at the complete stack trace and it should explain what's going wrong. – Jon Skeet May 11 '11 at 08:34
0

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
    }
}
Menahem
  • 3,974
  • 1
  • 28
  • 43