Вызывающий поток не может получить доступ к этому объекту, так как он принадлежит другому потоку. Как мне отредактировать изображение? - PullRequest
2 голосов
/ 11 мая 2011

я знаю, что таких вопросов много. Я хотел опубликовать, чтобы я мог поделиться своим конкретным вопросом, потому что я расстроен.

я запускаю поток, который запрашивает путь из базы данных и помещает его в элемент image.problem: я создал изображение в 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();

    }
}

Ответы [ 3 ]

14 голосов
/ 11 мая 2011

Как сказал Джон Скит, вы можете использовать Dispatcher.Invoke для назначения изображения, но этого недостаточно, потому что BitmapImage был создан в другом потоке. Чтобы иметь возможность использовать его в потоке пользовательского интерфейса, необходимо Freeze до:

logo.Freeze();
Action action = delegate { image1.Source = logo; };
image1.Dispatcher.Invoke(action);
3 голосов
/ 11 мая 2011

Вы используете Dispatcher, связанный с элементом управления, который вы хотите обновить:

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

Обратите внимание, что использование Thread.Sleep, подобного этому, для выполнения анимации вряд ли даст оченьхороший опыт ... тем более, что поток отображения затем должен извлечь URI для отображения изображения.Это не будет очень гладко.

0 голосов
/ 11 мая 2011

Я думаю, это потому, что вы не перенаправили вызов в поток пользовательского интерфейса. Вы можете сделать что-то в строке:

сохранить контекст в конструкторе,

// 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);
Кстати,

рекомендуется использовать операторы с SqlConnection и SqlDataReader. как в:

using (SqlConnection conn = new SqlConnection("conn string here"))
{
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
        // db access code
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...