user3196085
user3196085

Reputation:

How to call method to avoid cross threaded call

How to call method sendResponse to cross threaded call?

 void watcher_Created(object sender, FileSystemEventArgs e) {
            System.Diagnostics.Debug.WriteLine(e.FullPath);            
            sendResponse(e.FullPath); //this method must causes cross threaded call
        }

I was trying :

  Deployment.Current.Dispatcher.BeginInvoke(() => {                

            });

or Application.Current.Dispatcher.Invoke

But there is no Current .

How to deal with that?

I tried also:

        if (this.InvokeRequired) {...}

But there is no InvokeRequired.

EDIT I get unsupported exception when I create any object like Bitmap in sendResponse method. This method is called after firing event. So I thought it is crossthreading.

       void watcher_Created(object sender, FileSystemEventArgs e) {
            System.Diagnostics.Debug.WriteLine(e.FullPath);

            sendResponse(e.FullPath);
        }

 private void sendResponse(string path) {
            try {


                    BitmapImage bmi = new BitmapImage(new Uri(@path, UriKind.Relative));
                    byte[] data;
                    JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(bmi));
                    using (MemoryStream ms = new MemoryStream()) {
                        encoder.Save(ms);
                        data = ms.ToArray();
                    }
                clientStream.Write(data, 0, data.Length);
            } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e); }
        }

EDIT2 Client is widnows phone.. this(client) stopped worked after using code from the Nikita's answer(server stopped trhowing exceptions)

  try {
                            Deployment.Current.Dispatcher.BeginInvoke(() => {
                            MemoryStream stream = new MemoryStream(e.Buffer, e.Offset, e.BytesTransferred);


                                BitmapImage im = new BitmapImage();
                                im.SetSource(stream);

                                MainPage.page.imagePanel.Source = im;
                             });

Upvotes: 0

Views: 206

Answers (2)

noseratio
noseratio

Reputation: 61736

I don't have much of experience with WP8, but I think you should be able to use synchronization context, which is a universal concept. When your ViewModel or a UI element is created on the UI thread, remember the thread's current synchronization context:

SynchronizationContext _uiSyncContext;

// ...
_uiSyncContext = SynchronizationContext.Current;

Later from the background thread, use SynchronizationContext.Post (asynchronous callback) or SynchronizationContext.Send (synchronous callback) to execute code on the UI thread:

_uiSyncContext.Post((_) => { this.textBox.Text = "Hello"; }, null);

Upvotes: 0

Nikita B
Nikita B

Reputation: 3333

If you want to perform a call on UI thread, then you should save the reference to dispatcher by calling

 _dispatcher = Application.Current.Dispatcher;

on UI thread. Then you can access it on non-UI thread and use _dispatcher.BeginInvoke or _dispatcher.Invoke in your watcher_Created method.

If you simply want to make your code threadsafe - you can wrap the call in the lock statement:

private readonly object _sendLock = new object();

void watcher_Created(object sender, FileSystemEventArgs e) 
{
     System.Diagnostics.Debug.WriteLine(e.FullPath);            
     lock(_sendLock) 
     {
         sendResponse(e.FullPath);
     }
}

Edit: you do not need to use wpf components for opening a bitmap and you should not. Instead, for example, you can do the following:

using (MemoryStream ms = new MemoryStream())
using (Image img = Image.FromStream(File.OpenRead(@path)))
{
    img.Save(ms, ImageFormat.Jpeg);
    var data = ms.ToArray();
    clientStream.Write(data, 0, data.Length);
}

Upvotes: 1

Related Questions