I'm having a lot of pain porting my picturebox
from Windows Form
to WPF
.
My problem is not about the picturebox
itself, but I'm having troubles displaying an image
gotten from NetworkStream
from a Thread
into an Image
in WPF
.
I got this NetworkStream
from a TcpClient
connection client-server.
This is my Windows Form code (relevant part):
Thread getImage;
void StartReceiving(){
getImage = new Thread(ReceiveImage);
getImage.Start();
}
private void ReceiveImage()
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
while (client.Connected)
{
mainStream = client.GetStream();
try
{
pictureBox1.Image = (Image)binaryFormatter.Deserialize(mainStream);
}
catch (Exception ex) { }
}
}
This code works, I get image in loop every 100 ms and I need to update that source.
In WPF
I tried with an Image
and setting it's source (I tried both UriSource and StreamSource) but no success. I got thread exceptions
, "nothing appens
" errors, ...
This is my last code, it results into a Thread
error but I don't know what else to try to make it thread compliant. (I only posted the relevant part)
private readonly Thread getImage;
public SecondWindow(int port)
{
InitializeComponent();
client = new TcpClient();
getImage = new Thread(new ThreadStart(ReceiveImage));
while (!client.Connected)
{
server.Start();
client = server.AcceptTcpClient();
}
getImage.Start();
}
private void ReceiveImage()
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
BitmapImage imgSrc = new BitmapImage();
while (client.Connected)
{
var mainStream = client.GetStream();
int loop = 0;
while (!mainStream.DataAvailable && loop < 500)
{
loop++;
Thread.Sleep(10);
}
if (mainStream.DataAvailable)
{
try
{
imgSrc = new BitmapImage();
imgSrc.BeginInit();
imgSrc.StreamSource = mainStream;
imgSrc.CacheOption = BitmapCacheOption.OnLoad;
imgSrc.EndInit();
if (imgSrc.CanFreeze && !imgSrc.IsFrozen)
imgSrc.Freeze();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (displayImage.Dispatcher.CheckAccess())
{
displayImage.Source = imgSrc;
}
else
{
Action act = () => { displayImage.Source = imgSrc; };
displayImage.Dispatcher.BeginInvoke(act);
}
}
}
}
In the above code I have 2 problems: 1st that imgSrc
can never freeze
2nd (probably a direct consequence of 1st problem), I get InvalidOperationException
The calling thread cannot access this object because a different thread owns it
Thanks all for the support
I solved!! the solution was using some other methods in order to deserialize the full stream and then apply it to the image source!
This might not be the best solution but this answer pointed me to the end of this agony
This is my working code:
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteObject(IntPtr value);
private void ReceiveImage()
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
System.Drawing.Image imgSrc;
while (client.Connected)
{
var mainStream = client.GetStream();
int loop = 0;
while (!mainStream.DataAvailable && loop < 500)
{
loop++;
Thread.Sleep(10);
}
if (mainStream.DataAvailable)
{
try
{
imgSrc = (System.Drawing.Image)binaryFormatter.Deserialize(mainStream);
var bitmap = new Bitmap(imgSrc);
IntPtr bmpPt = bitmap.GetHbitmap();
BitmapSource bitmapSource =
System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmpPt,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
//freeze bitmapSource and clear memory to avoid memory leaks
if (bitmapSource.CanFreeze && !bitmapSource.IsFrozen)
bitmapSource.Freeze();
DeleteObject(bmpPt);
if (displayImage.Dispatcher.CheckAccess())
{
displayImage.Source = bitmapSource;
}
else
{
Action act = () => { displayImage.Source = bitmapSource; };
displayImage.Dispatcher.BeginInvoke(act);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}