WPF UI not responsive in spite of process running in a seperate thread. Why?
Using threading in WPF makes no difference for me. The UI continues to be not responsive.
This is my code:
private void button1_Click_1(object sender, RoutedEventArgs e)
{
Thread th = new Thread(new ThreadStart(LoadImages));
th.Start();
}
void LoadImages()
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, new System.Windows.Forms.MethodInvoker(delegate() {
IService1 svc = ConnectAndGetObject();
foreach (byte[] imgbytes in svc.GetImageDateWise(datePicker1.DisplayDate, DateTime.Now, "test"))
{
using (MemoryStream mem = new MemoryStream(imgbytes))
{
BitmapImage jpgimage = new BitmapImage();
jpgimage.BeginInit();
jpgimage.CacheOption = BitmapCacheOption.OnLoad;
jpgimage.StreamSource = mem;
jpgimage.EndInit();
// PngBitmapDecoder decodejpg = new PngBitmapDecoder(mem, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand);
Image wpfimage = new Image();
wpfimag开发者_如何学Goe.Source = jpgimage.Clone();
lbx.Items.Add(wpfimage);
lbx.UpdateLayout();
Thread.Sleep(1000);
}
}
}));
}
Updated working code:
List<MemoryStream> mems = new List<MemoryStream>();
void LoadImages()
{
IService1 svc = ConnectAndGetObject();
foreach (byte[] imgbytes in svc.GetImageDateWise(GetDate(), DateTime.Now, "test"))
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() {
mems.Add(new MemoryStream(imgbytes));
BitmapImage jpgimage = new BitmapImage();
jpgimage.BeginInit();
jpgimage.CacheOption = BitmapCacheOption.None;
jpgimage.StreamSource = mems[mems.Count-1];
jpgimage.EndInit();
Image wpfimage = new Image();
wpfimage.Source = jpgimage.Clone();
lbx.Items.Add(wpfimage);
lbx.UpdateLayout();
Thread.Sleep(500);
}));
}
mems.Clear();
}
In your code the entire body of LoadImages
is Invoked right back to the main thread. So you do not have a multi-threaded solution at all, just a complicated one.
Here is my stab at it:
// untested
void LoadImages()
{
// this.Dispatcher.Invoke(DispatcherPriority.Normal,
// new System.Windows.Forms.MethodInvoker(delegate() {
IService1 svc = ConnectAndGetObject();
foreach (byte[] imgbytes in svc.GetImageDateWise(datePicker1.DisplayDate, DateTime.Now, "test"))
{
using (MemoryStream mem = new MemoryStream(imgbytes))
{
BitmapImage jpgimage = new BitmapImage();
jpgimage.BeginInit();
jpgimage.CacheOption = BitmapCacheOption.OnLoad;
jpgimage.StreamSource = mem;
jpgimage.EndInit();
// only invoke the part actually touching the UI
this.Dispatcher.Invoke(DispatcherPriority.Normal,
new System.Windows.Forms.MethodInvoker(delegate() {
Image wpfimage = new Image();
wpfimage.Source = jpgimage; //.Clone();
lbx.Items.Add(wpfimage);
lbx.UpdateLayout(); } ));
Thread.Sleep(1000);
}
}
// }));
}
The problem is that the first thing your non UI thread does is invoke a delegate on the UI thread. The net result is a lot of overhead with no cocurrency at all.
Reorg your code so that only UI tasks are done on the UI thread.
void LoadImages()
{
IService1 svc = ConnectAndGetObject();
...
Dispatcher.Invoke( () => lbx.Items.Add(wpfimage));
....
}
You're doing too much in your delegate. This might be the cause of your problems, plus the 1 second sleep you have in there.
Just have the code that updates the list box in the delegate:
lbx.Items.Add(wpfimage);
lbx.UpdateLayout();
Failing that raise an event in your thread and subscribe to it in your main application and update the UI from that.
You'll need a method along these lines:
private void ImageAdded_EventHandler(object sender, ImageAddedEventArgs e)
{
Action action = () => ImageAdded(e.Image);
if (Dispatcher.CheckAccess())
{
action();
}
else
{
Dispatcher.Invoke(DispatcherPriority.Normal, action);
}
}
Where ImageAddedEventArgs
is a class based on EventArgs
that has a property of the image data.
精彩评论