How to call method to avoid cross threaded call - c#

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

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

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

Related

C# WPF MjpegStream. video appears to pause when writing and reading data on TCP/IP packets

My window should display the status of the video stream
and the data sent and received in tcpip.
Every two seconds, the video appears to pause
when writing and reading data on TCP/IP.
How can we solve this phenomenon?
For your information,
The application programs that deal with video stream,
the stream look natural regardless of the tcpip I send and receive.
enter code here
private MJPEGStream m_Stream;
private DispatcherTimer m_Timer = null;
public TcpClient clientTcp = new TcpClient;
public NetworkStream streamTcp = new NetworkStream;
public MainWindow()
{
InitializeComponent();
IpCamera();
OpenTcpIpCommuncation();
}
public void OpenTcpIpCommuncation()
{
var result= clientTcp.BeginConnect("192.168.0.3","24", null, null);
streamTcp = clientTcp.GetStream();
m_Timer = new DispatcherTimer();
m_Timer.Interval = TimeSpan.FromSeconds(2.0);
m_Timer.Tick += new EventHandler(TcpTimer_Tick);
m_Timer.Start();
}
private void TcpTimer_Tick(object sender, EventArgs e)
{
for (int=0; i<20; i++)
{
stream.Write(send_status_packet, 0, Length);
Thread.Sleep(50);
NumberOfBytes = stream.Read(data, 0, data.Length);
}
// label, text etc upate from data
}
public void IpCamera()
{
string sUrl = "http://192.168.0.100:8080" "//" + kCameraInfo.SubUrl;
m_Stream = new MJPEGStream(sUrl);
m_Stream.Login = "admin";
m_Stream.Password = "1234";
m_Stream.NewFrame += Camera_Frame;
m_Stream.Start();
}
private void Camera_Frame(object sender, NewFrameEventArgs eventArgs)
{
try
{
BitmapImage bi;
using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
{
bi = bitmap.ToBitmapImage();
}
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate { imgCamera.Source = bi; }));
}
catch (Exception e)
{
}
}
Thread.Sleep blocks the UI thread.
Not sure why exactly you have this for loop, but it blocks the UI thread for at least 20 * 50 milliseconds, i.e. one second.
As a workaround, you may declare the Tick event handler async and use Task.Delay instead. You may perhaps also use the async versions of the Write and Read methods:
private async void TcpTimer_Tick(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
await stream.WriteAsync(send_status_packet, 0, Length);
await Task.Delay(50);
NumberOfBytes = await stream.ReadAsync(data, 0, data.Length);
}
...
}
It might also be better not have the loop at all, and run the timer at a shorter interval.

InvalidOperationException while saving a bitmap and using graphics.copyFromScreen parallel-y

I am writing an application to capture the screen using the CopyFromScreen method, and also want to save the image I capture to send over my local network.
So, I am trying store the captured screen on one bitmap, and save another bitmap, which is the previously captured screen, on two threads.
However, this is throwing an InvalidOperationException, which says object is currently in use elsewhere. The exception is thrown by System.Drawing.dll.
I have tried locking, and am using separate bitmaps for saving and capturing the screen. How do I stop this from happening? Relevant code:
Bitmap ScreenCapture(Rectangle rctBounds)
{
Bitmap resultImage = new Bitmap(rctBounds.Width, rctBounds.Height);
using (Graphics grImage = Graphics.FromImage(resultImage))
{
try
{
grImage.CopyFromScreen(rctBounds.Location, Point.Empty, rctBounds.Size);
}
catch (System.InvalidOperationException)
{
return null;
}
}
return resultImage;
}
void ImageEncode(Bitmap bmpSharedImage)
{
// other encoding tasks
pictureBox1.Image = bmpSharedImage;
try
{
Bitmap temp = (Bitmap)bmpSharedImage.Clone();
temp.Save("peace.jpeg");
}
catch (System.InvalidOperationException)
{
return;
}
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Interval = 30;
timer1.Start();
}
Bitmap newImage = null;
private async void timer1_Tick(object sender, EventArgs e)
{
//take new screenshot while encoding the old screenshot
Task tskCaptureTask = Task.Run(() =>
{
newImage = ScreenCapture(_rctDisplayBounds);
});
Task tskEncodeTask = Task.Run(() =>
{
try
{
ImageEncode((Bitmap)_bmpThreadSharedImage.Clone());
}
catch (InvalidOperationException err)
{
System.Diagnostics.Debug.Write(err.Source);
}
});
await Task.WhenAll(tskCaptureTask, tskEncodeTask);
_bmpThreadSharedImage = newImage;
}
I reproduced your problem in a nutshell by creating a simple winforms project with a single button on it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => SomeTask());
}
public void SomeTask() //this will result in 'Invalid operation exception.'
{
var myhandle = System.Drawing.Graphics.FromHwnd(Handle);
myhandle.DrawLine(new Pen(Color.Red), 0, 0, 100, 100);
}
}
In order to fix this you need to do the following:
public partial class Form1 : Form
{
private Thread myUIthred;
public Form1()
{
myUIthred = Thread.CurrentThread;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => SomeTask());
}
public void SomeTask() // Works Great.
{
if (Thread.CurrentThread != myUIthred) //Tell the UI thread to invoke me if its not him who is running me.
{
BeginInvoke(new Action(SomeTask));
return;
}
var myhandle = System.Drawing.Graphics.FromHwnd(Handle);
myhandle.DrawLine(new Pen(Color.Red), 0, 0, 100, 100);
}
}
The issue is (as Spektre implied) a result of trying to call a UI method from a non-UI thread. The 'BeginInvoke' is actually `this.BeginInvoke' and 'this' is the form which was created by the UI thread and therefore all works.
I do not code in C# so I may be wrong here but I assume you are using Windows...
Accessing any visual components (like GDI Bitmap or window ...) is not safe outside WndProc function. So if you are using GDI bitmap (bitmap with device context) or rendering/accessing any visual component from your window inside any thread then there is your problem. After that any call to WinAPI in your app can throw an exception (even unrelated to graphics)
So try to move any such code into your WndProc function. In case you do not have access to it use any event of your window (like OnTimer or OnIdle).

Setting source of an Image control from Memory Stream using Non-UI thread in WPF

I am Capturing image from a finger print Scanner and i want to display the captured image live in an Image control.
//Onclick of a Button
Thread WorkerThread = new Thread(new ThreadStart(CaptureThread));
WorkerThread.Start();
So i created a thread as above and called the method that captures the image from the device and sets the source of the Image control as follows.
private void CaptureThread()
{
m_bScanning = true;
while (!m_bCancelOperation)
{
GetFrame();
if (m_Frame != null)
{
MyBitmapFile myFile = new MyBitmapFile(m_hDevice.ImageSize.Width, m_hDevice.ImageSize.Height, m_Frame);
MemoryStream BmpStream = new MemoryStream(myFile.BitmatFileData);
var imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = BmpStream;
imageSource.EndInit();
if (imgLivePic.Dispatcher.CheckAccess())
{
imgLivePic.Source = imageSource;
}
else
{
Action act = () => { imgLivePic.Source = imageSource; };
imgLivePic.Dispatcher.BeginInvoke(act);
}
}
Thread.Sleep(10);
}
m_bScanning = false;
}
Now when i Run the project it throws an Exception on line Action act = () => { imgLivePic.Source = imageSource; }; Saying "The Calling thread Can Not Access this object because a different thread owns it".
i did some research and i found out that if i want to use UI controls over a NON-UI thread i should use Dispatcher.Invoke method, which as you can see i have but i am still getting the same exception.
can someone please tell me what am i doing wrong?
The BitmapImage does not necessarily need to be created in the UI thread. If you Freeze it, it will later be accessible from the UI thread. Thus you will also reduce the resource consumption of your application. In general, you should try to freeze all Freezables if possible, especially bitmaps.
using (var bmpStream = new MemoryStream(myFile.BitmatFileData))
{
imageSource.BeginInit();
imageSource.StreamSource = bmpStream;
imageSource.CacheOption = BitmapCacheOption.OnLoad;
imageSource.EndInit();
}
imageSource.Freeze(); // here
if (imgLivePic.Dispatcher.CheckAccess())
{
imgLivePic.Source = imageSource;
}
else
{
Action act = () => { imgLivePic.Source = imageSource; };
imgLivePic.Dispatcher.BeginInvoke(act);
}
The BitmapImage itself needs to be constructed on the Dispatcher thread.

using the invoke to access a textbox on the form

i'm writing a simple filestream program in C# using asynchronous reading which uses a thread other than the main thread for its callback.but i'm getting cross-thread exception when i try to write my filecontent in a text box.
here is my program:
using System;
namespace Filestream
{
public partial class Form1 : Form
{
FileStream fs;
byte[] fileContents;
AsyncCallback callback;
public Form1()
{
InitializeComponent();
}
private void synbtn_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
callback = new AsyncCallback(fs_StateChanged);
fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
fileContents = new Byte[fs.Length];
fs.BeginRead(fileContents, 0, (int)fs.Length, callback, null);
}
public void fs_StateChanged(IAsyncResult ar)
{
if (ar.IsCompleted)
{
*textBox1.Text = Encoding.UTF8.GetString(fileContents);*
fs.Close();
}
}
}
}
the part with the star is the part that i'm getting the exception.i tried to use the invoke but i had no luck.can someone correct this part of the code with invoke so i don't get the error.
thanks.
try this.
if(textbox1.InvokeRequired)
{
textbox1.Invoke(new MethodInvoker(() => textBox1.Text = Encoding.UTF8.GetString(fileContents)));
}
else
{
textBox1.Text = Encoding.UTF8.GetString(fileContents);
}
To Expand on Ram's answer
//Can this thread make updates to textbox1?
if(textbox1.InvokeRequired)
{
//No then use the invoke method to update textbox1
textbox1.Invoke(new MethodInvokernew MethodInvoker(() => textBox1.Text = Encoding.UTF8.GetString(fileContents)));
}else{
//Yes then update textbox1
textBox1.Text = Encoding.UTF8.GetString(fileContents);
}
Explanation:
Updates to a UI control must be done on the thread that created the UI control. To test if the current thread is allowed to update a particular UI control call the InvokeRequired method on the control. Invoke can then be used to call a method on using the thread that can update the control

Asynchronously Loading a BitmapImage in C# using WPF

What's the best way to asynchronously load an BitmapImage in C# using WPF?
I was just looking into this and had to throw in my two cents, though a few years after the original post (just in case any one else comes looking for this same thing I was looking into).
I have an Image control that needs to have it's image loaded in the background using a Stream, and then displayed.
The problem that I kept running into is that the BitmapSource, it's Stream source and the Image control all had to be on the same thread.
In this case, using a Binding and setting it's IsAsynch = true will throw a cross thread exception.
A BackgroundWorker is great for WinForms, and you can use this in WPF, but I prefer to avoid using the WinForm assemblies in WPF (bloating of a project is not recommended, and it's a good rule of thumb too). This should throw an invalid cross reference exception in this case too, but I didn't test it.
Turns out that one line of code will make any of these work:
//Create the image control
Image img = new Image {HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, VerticalAlignment = System.Windows.VerticalAlignment.Stretch};
//Create a seperate thread to load the image
ThreadStart thread = delegate
{
//Load the image in a seperate thread
BitmapImage bmpImage = new BitmapImage();
MemoryStream ms = new MemoryStream();
//A custom class that reads the bytes of off the HD and shoves them into the MemoryStream. You could just replace the MemoryStream with something like this: FileStream fs = File.Open(#"C:\ImageFileName.jpg", FileMode.Open);
MediaCoder.MediaDecoder.DecodeMediaWithStream(ImageItem, true, ms);
bmpImage.BeginInit();
bmpImage.StreamSource = ms;
bmpImage.EndInit();
//**THIS LINE locks the BitmapImage so that it can be transported across threads!!
bmpImage.Freeze();
//Call the UI thread using the Dispatcher to update the Image control
Dispatcher.BeginInvoke(new ThreadStart(delegate
{
img.Source = bmpImage;
img.Unloaded += delegate
{
ms.Close();
ms.Dispose();
};
grdImageContainer.Children.Add(img);
}));
};
//Start previously mentioned thread...
new Thread(thread).Start();
Assuming you're using data binding, setting Binding.IsAsync property to True seems to be a standard way to achieve this.
If you're loading the bitmap in the code-behind file using background thread + Dispatcher object is a common way to update UI asynchronous
This will allow you to create the BitmapImage on the UI thread by using the HttpClient to do the async downloading:
private async Task<BitmapImage> LoadImage(string url)
{
HttpClient client = new HttpClient();
try
{
BitmapImage img = new BitmapImage();
img.CacheOption = BitmapCacheOption.OnLoad;
img.BeginInit();
img.StreamSource = await client.GetStreamAsync(url);
img.EndInit();
return img;
}
catch (HttpRequestException)
{
// the download failed, log error
return null;
}
}
To elaborate onto aku's answer, here is a small example as to where to set the IsAsync:
ItemsSource="{Binding IsAsync=True,Source={StaticResource ACollection},Path=AnObjectInCollection}"
That's what you would do in XAML.
BitmapCacheOption.OnLoad
var bmp = await System.Threading.Tasks.Task.Run(() =>
{
BitmapImage img = new BitmapImage();
img.BeginInit();
img.CacheOption = BitmapCacheOption.OnLoad;
img.UriSource = new Uri(path);
img.EndInit();
ImageBrush brush = new ImageBrush(img);
}
Use or extend System.ComponentModel.BackgroundWorker:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Personally, I find this to be the easiest way to perform asynchronous operations in client apps. (I've used this in WinForms, but not WPF. I'm assuming this will work in WPF as well.)
I usually extend Backgroundworker, but you dont' have to.
public class ResizeFolderBackgroundWorker : BackgroundWorker
{
public ResizeFolderBackgroundWorker(string sourceFolder, int resizeTo)
{
this.sourceFolder = sourceFolder;
this.destinationFolder = destinationFolder;
this.resizeTo = resizeTo;
this.WorkerReportsProgress = true;
this.DoWork += new DoWorkEventHandler(ResizeFolderBackgroundWorker_DoWork);
}
void ResizeFolderBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
DirectoryInfo dirInfo = new DirectoryInfo(sourceFolder);
FileInfo[] files = dirInfo.GetFiles("*.jpg");
foreach (FileInfo fileInfo in files)
{
/* iterate over each file and resizing it */
}
}
}
This is how you would use it in your form:
//handle a button click to start lengthy operation
private void resizeImageButtonClick(object sender, EventArgs e)
{
string sourceFolder = getSourceFolderSomehow();
resizer = new ResizeFolderBackgroundWorker(sourceFolder,290);
resizer.ProgressChanged += new progressChangedEventHandler(genericProgressChanged);
resizer.RunWorkerCompleted += new RunWorkerCompletedEventHandler(genericRunWorkerCompleted);
progressBar1.Value = 0;
progressBar1.Visible = true;
resizer.RunWorkerAsync();
}
void genericRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Visible = false;
//signal to user that operation has completed
}
void genericProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
//I just update a progress bar
}

Categories

Resources