Ошибка потоковой работы WPF - PullRequest
0 голосов
/ 06 марта 2012

Я использую EmguCV в WPF, и я нашел этот пример tp capture image, я хочу использовать bs1 в моем другом методе Method3 (), но я получаю сообщение об ошибке, что объект принадлежит другому потоку, любой знает, чтоэто проблема?bs1, в конце концов, является глобальной переменной

  BitmapSource bs1;

 private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        capture = new Capture();       ///capture image

        timer = new DispatcherTimer();       // timer object
        timer.Interval = new TimeSpan(500);
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();

    }
    void timer_Tick(object sender, EventArgs e)
    {
        using (  Image<Bgr, byte> Frame = capture.QueryFrame())
        {
            if (Frame != null)
            {
                bs1 = ToBitmapSource(Frame);
webcam.Source = ToBitmapSource(Frame); // ToBitmapSource convert image to bitmapsource webcam is a picture in mainwindow
                 Frame.Save("fg.jpeg");   //this work but use lot of processing 

            }
        }
    }


public void Method3_click (...)
{
    use_of_bs1(bs1);
}


  private void use_of_bs1()
    {

        data.Text = "waiting...";

        System.Threading.ThreadPool.QueueUserWorkItem(Startwork);
    }


    private void Startwork(object state)
    {

        try
        {
            _work = _worker.bs1_analysis(bs1);      // it is where bs1 giving thread errorbs1_analysis is library function
        }
        catch (Exception ex)
        {
            Dispatcher.BeginInvoke(new ShowworkInformationDelegate(ShowworkInformation));
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
        Dispatcher.BeginInvoke(new ShowWorkInformationDelegate(ShowWorkInformation));

    }

/// Функция ToBitmapsource равна

public static BitmapSource ToBitmapSource(Emgu.CV.IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap();
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ptr, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(ptr);
            return bs;
        }
    }

Ответы [ 4 ]

2 голосов
/ 06 марта 2012

В WPF элементы пользовательского интерфейса могут быть доступны и использоваться только тем потоком, который их создал (за исключением замораживаемых элементов). В вашем коде bs1 создается в основном потоке пользовательского интерфейса. Таймер, являющийся другим потоком, не может получить доступ к этому ресурсу. Всякий раз, когда вы хотите что-то сделать с элементом пользовательского интерфейса, который создается в основном потоке пользовательского интерфейса, выполните следующие действия:

Dispatcher.Invoke(DispatcherPriority.Normal, new Action(()=>DoSomeCodeWithUIElement()));

Используйте Dispatcher.Invoke, если вы хотите, чтобы операция выполнялась синхронно, или Dispatcher.BeginInvoke, если вы хотите асинхронный вызов. Где DoSomeCodeWithUIElement - это метод, с помощью которого вы получаете доступ и, в конечном итоге, обновляете элементы пользовательского интерфейса.

1 голос
/ 07 марта 2012

Если вы создаете ресурс wpf и хотите использовать его в другом потоке, вы можете вызвать Freeze() для объекта перед его передачей. Это сделает его неизменным и законным для использования в другом потоке.

1 голос
/ 06 марта 2012

В событии timer (timer_Tick) вы находитесь в другом потоке, который принадлежит bs1

Вам необходимо выполнить событие в главном потоке. Что-то вроде:

void timer_Tick(object sender, EventArgs e)
{
    Dispatcher.Invoke(DispatcherPriority.Normal,
            new Action(
                delegate {
    using (  Image<Bgr, byte> Frame = capture.QueryFrame())
    {
        if (Frame != null)
        {
            bs1 = ToBitmapSource(Frame);
            webcam.Source = ToBitmapSource(Frame); // ToBitmapSource convert image to bitmapsource
            Frame.Save("fg.jpeg");   //this work but use lot of processing 

        }
    }}));
}
1 голос
/ 06 марта 2012

Из того, что вы описали, bs1 был связан с Window.Dispatcher, поэтому при обращении к нему внутри Method3() возникло исключение.Чтобы решить эту проблему, вы можете сделать что-то вроде этого

public void Method3()
{
    Action<BitmapSource> useBs1 = (source) =>  use_of_bs1(source);
    if(Thread.CurrentThread == this.Dispatcher.Thread)
      {

    useBs1(bs1);
}
else
{
   this.Dispatcher.Invoke(DispatcherPriority.Normal,userBs1, bs1);
}


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...