100% responsive interface in WPF

I have a WPF application that uses a component that sends a bitmap to my application as they appear, I get these bitmaps in the deletion that I pass to this component.

I created a new thread for this process, and it works very well, bitmaps come as a MemoryStream, and I just create a BitmapSource object from this thread inside the method call Dispatcher.BeginInvoke. After I have a BitmapSource object, I add them to the StackPanel so that the user can see the queue of images available for work. So far so good ...

The problem is that these bitmaps are quite large, for example 3000x2000 + pixels, and it takes about 50 ~ ms to create these bitmaps and add to the queue, and when this code is executed, onde inside the BeginInvoke call, it blocks the user interface for this time, causing a very annoying behavior, (to reproduce this, just call Thread.Sleep(50)every 5 seconds).

How can I fix this so that the user always responds?

thanks!

+3
source share
4 answers

There are two ideas you can consider:

  • BitmapSource Dispatcher.Invoke. , . , , BitmapSource .

  • , , StackPanel 3000x2000? , , .

# 1 :

Window1.xaml

<Window x:Class="BitmapFrameDemo.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Grid>
        <Image Name="image"/>
    </Grid>
</Window>

Window1.xaml.cs

using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace BitmapFrameDemo {

    public partial class Window1 : Window {

        private Thread      thread      = null;
        private Dispatcher  dispatcher  = null;

        private void ThreadMain() {
            // obtain the image memory stream
            WebRequest          request     = WebRequest.Create("http://stackoverflow.com/content/img/so/logo.png");
            WebResponse         response    = request.GetResponse();
            Stream              stream      = response.GetResponseStream();

            // create a bitmap source while still in the background thread
            PngBitmapDecoder    decoder     = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
            BitmapFrame         frame       = decoder.Frames[0];

            // freeze the bitmap source, so that we can pass it to the foreground thread
            BitmapFrame         frozen      = (BitmapFrame) frame.GetAsFrozen();
            dispatcher.Invoke(new Action(() => { image.Source = frozen; }), new object[] { });
        }

        public Window1() {
            InitializeComponent();

            dispatcher = Dispatcher.CurrentDispatcher;
            thread = new Thread(new ThreadStart(this.ThreadMain));
            thread.Start();
        }
    }
}

alt text http://www.freeimagehosting.net/uploads/66bdbce78a.png

+4

.

-, BackgroundWorker MemoryStream Bitmap.

- ThreadPool.

+1

, , , IsAsync True . PriorityBinding , , , .

<StackPanel>
    <Image>
        <Image.Source>
            <PriorityBinding>
                <Binding Path="SlowImage"
                         IsAsync="True" />
                <Binding Path="DefaultImage" />
            </PriorityBinding>
        </Image.Source>
    </Image>
</StackPanel>


public partial class Window1 : Window, INotifyPropertyChanged
{

    public Window1()
    {
        InitializeComponent();

        DefaultImage = new BitmapImage(new Uri("http://stackoverflow.com/content/img/so/logo.png"));

        SlowImage = new BitmapImage(new Uri("http://serverfault.com/content/img/sf/logo.png"));

        this.DataContext = this;
    }

    private BitmapImage myDefaultImage;
    public BitmapImage DefaultImage
    {
        get { return this.myDefaultImage; }
        set
        {
            this.myDefaultImage = value;
            this.NotifyPropertyChanged("Image");
        }
    }

    private BitmapImage mySlowImage;
    public BitmapImage SlowImage
    {
        get
        {
            Thread.Sleep(5000);
            return this.mySlowImage;
        }
        set
        {
            this.mySlowImage = value;
            this.NotifyPropertyChanged("SlowImage");
        }
    }

    #region INotifyPropertyChanged Members

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}
+1

Source: https://habr.com/ru/post/1711690/


All Articles