调用线程无法访问该对象,因为另一个线程拥有它。如何编辑图像?

发布于 2024-11-06 13:06:33 字数 2462 浏览 0 评论 0原文

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

我正在运行一个线程,该线程从数据库查询路径并将其放入图像元素中。问题是,我在 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();

    }
}

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

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

锦上情书 2024-11-13 13:06:33

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

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

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);
待"谢繁草 2024-11-13 13:06:33

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

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

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

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.

茶底世界 2024-11-13 13:06:33

我认为这是因为您没有将调用编组到 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);

顺便说一句,将 using 语句与 SqlConnectionSqlDataReader 一起使用是一个很好的做法。如:

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

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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文