3

I would like to update my UI through another class, I have tried doing this by creating a form1 object and using a method to update the textbox. This leads to an error which informs me that my device is not properly running.

So basically how do I update a textbox on my Form1 using my samplegrabber.cs class? This class is called constantly, however I only need to use the string .

The ISampleGrabber class calls the SampleCB method which consists of:

public int SampleCB(double sampletime, IMediaSample sample)
    {
        if (sample == null)
        {
            return -1;
        }
        try
        {
            int length = sample.GetActualDataLength();
            IntPtr buffer;          
            if (sample.GetPointer(out buffer) == 0 && length > 0)
            {
                Bitmap bitmapOfFrame = new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, buffer);
            }                
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        Marshal.ReleaseComObject(sample);
        return 0;
    }

The form1 object is created within the if statement, the erroroccurs even if I create the object (Even without the f1.updateTextBox(id);) line.

The `updateTextBox1' is created in Form1:

    public void updateTextBox1(string id)
    {
        textBox1.Text = id;
    }

The error I receive is as follows:

COMException(0x8007001F)A device attached to the system is not functioning properly.

Max
  • 12,622
  • 16
  • 73
  • 101
legohead
  • 530
  • 2
  • 8
  • 23

1 Answers1

2

SampleCB is called on a side thread. You should not do any UI related operations in this callback, instead you might want to store the values in member variables and indicate that you need to continue on the UI thread, e.g. by posting yourself a message and then handling it on the correct thread.

Community
  • 1
  • 1
Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • I have tried to use the examples given however can not seem to get it to work. Within my `SampleCB`, where currently a messagebox is being shown, how would I say (For lack of a better phrase) 'I'm done, this is the string'? – legohead Nov 27 '13 at 19:07
  • 1
    You have choices how to do it but - because you look for a simple thing - let me offer you not the best but supposedly easiest to understand. In your callback you store the string in your internal variable, and you set another `bool` variable to `true`. Then on your window/form you have a timer that calls its event back at regular intervals, and from there when you see this `true`, you are good to go with the stored string too. – Roman R. Nov 27 '13 at 19:28
  • By 'calls its event back' do you mean create a new function within the ISampleGrabber class and call that or? – legohead Nov 27 '13 at 19:43
  • No, I mean adding [WinForms Timer](http://msdn.microsoft.com/en-us/library/system.windows.forms.timer%28v=vs.110%29.aspx) to call back on "proper" UI thread. This has to be set once well in advance, not from SG callback (already running on "wrong" thread). – Roman R. Nov 27 '13 at 19:50
  • From what I am understanding, do you mean add a timer to my UI Thread/First Form? What event am I calling back? Sorry about not understanding, I am very new to using multiple threads at once and how the different ones share data. – legohead Nov 27 '13 at 19:58
  • Timer's `Tick` event is called on UI thread. This is your strategy here: you do minimal work on SG callback (just storing values into safe place) and then timer's event provides you with a chance to take over on "correct" thread (this is a simplified version: once you are OK with this, you will need to read up on synchronization and how to protect this data using for example [`ReaderWriterLock`](http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx)). – Roman R. Nov 27 '13 at 20:07
  • So, on my UI thread I would start a timer, and set an event handler which would go off every 5 seconds etc. Then within my timer event how would I check the sampleGrabber thread to check for this bool to see if I can access the string? I can only think of creating a class object and calling the `SampleCB`, but wouldn't this create an error as it is already being called where I tell the sampleGrabber which callback to use? – legohead Nov 27 '13 at 20:15
  • Do you know of any code examples thats how what you are suggesting? I think I may understand it more if I see it in action – legohead Nov 27 '13 at 20:19
  • Ok, so I have set up my timer but how would I go about extracting the relevant information from the `SampleCB`. – legohead Nov 28 '13 at 01:14
  • Instead of using a timer is it possible to invoke the UI thread? – legohead Nov 29 '13 at 17:09
  • The goal is not touch UI objects from side thread callback. There are many ways to achieve this, I suggested timer not because it's the best way (it's not) but because it's supposedly easy to understand. If you don't like it, you might need to figure out anything else - message posting, synchronization objects, .NET sync helpers etc. It goes pretty much out of the scope of original question. – Roman R. Nov 29 '13 at 17:18
  • I did try to use the timer method but I did not see how I would extract the information form the `SampleCB` and send it to Form1 without doing `Form1 f1 = new Form1();` which was causing the original error. – legohead Nov 29 '13 at 17:26
  • Could you also explain message posting, I did not see how to use the two links you gave me? Thanks – legohead Nov 29 '13 at 17:29