Saturday, September 14, 2013

Directly Accessing Dispatcher from Observables may freeze UI

The following code made UI not responsive, can not move either main or popup windows.
It seems that directly hitting dispatcher can overwhelm it. Consider using BlockingCollection.



// Observer Popup window every 5 seconds. e.g. RFQ and its updates come in during peak market hours.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Observable.Interval(TimeSpan.FromSeconds(5)).Subscribe((t)=>
            {
                this.Dispatcher.Invoke(() => { (new Window1() { Title = t.ToString() }).Show(); });
               // this.Dispatcher.BeginInvoke(new Action(() => { (new Window1() { Title = t.ToString() }).Show(); }));  // same behavior

        });



// each window may take long time to PopUp during data delay or binding on UI Thread.
   public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            Thread.Sleep(5000); // simulating delay on UI Thread.
        }
    }

One solution is to use multiple dispatchers

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            Observable.Interval(TimeSpan.FromSeconds(5)).Subscribe((t) =>
            {
                Thread th = new Thread(new ThreadStart(show));
                th.SetApartmentState(ApartmentState.STA);
                th.IsBackground = true;
                th.Start();

            });
        }
        void show()
        {

            Windows w= new Window1() { Title = DateTime.Now.ToString() });
w.Show();
  w.Closed += (sender2, e2) =>
      w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run(); }

No comments: