3

I want to know what is the best solution to improve my WPF application.

I know that WPF forces you to do all the UI work on the thread that created the UI. This is a major problem for me, because my UI is very huge and I only have 1 window, so I cannot split 1 thread per window.

When I do pan and zoom, everything needs to be refresh every time, one of my CPU hit 100% usage until all is done.

So I'll try to explain what I have in my application:

  • 1 window (size of the screen)
  • Virtual panel, 12000 px X 12000 px (where I do pan and zoom)
  • About 2000 controls (button, switch, and some other complex controls)
  • Behind my controls, I have a big Bitmap for my background, but I split my background in something like 100 smaller bitmap that I stack (because 1 bitmap of 12k pixels by 12k pixels crash my app)
  • 10 virtual displays, connected to a distant computer (who feed the bitmap) and refresh their content every 50 ms
  • .NET 4.0, multitouch application

So just my application where I can do pan and zoom (without the 10 displays), there is a lot of lag du to the amount of controls, and when I put the display, it double the lag...

My application takes about 1.5 gb of virtual memory.

I searched to use the dispatcher to makes threads when I can but I don't find what I want... everywhere they talked about 1 thread/window... but I only have 1 Window, don't know what to do.

  • I cannot split into smaller window.
  • I cannot reduce the amount of controls, or the refresh time.
  • I cannot change technology (WPF)

So here is the real question: Where can I create new threads to help my render time? To split the job to different CPU...

I found different website where they talked about this... but not answering my question:

Running WPF Application with Multiple UI Threads

MSDN

Working With The WPF Dispatcher

mlemay
  • 1,622
  • 2
  • 32
  • 53
  • I read somewhere that UI objects can be created on a different threads. I need to find out. Otherwise I think Kent's suggestion about Virtualization is something to look at. – MBen Jul 09 '12 at 12:08
  • 1.5GB.. what is the Top3 memory consuming object types? (memory profiling required). – sll Jul 09 '12 at 12:16
  • 1
    Have a look at my [question](http://stackoverflow.com/questions/7964445/responsive-ui-tips). There are some nice hints to improve your UI's responsiveness. – Willem Jul 09 '12 at 12:27
  • Faster machine with a gaming level video card. – paparazzo Jul 09 '12 at 12:36
  • But all the work is done by the CPU, the video card do nothing and yes I'm tier 2.... – mlemay Jul 09 '12 at 12:37
  • XNA might be the right tool: you're basically modelling a game-like application (2000 controls is *a hell of a UI*), so you might aswell treat it like one. And you could delegate some work on the GPU (I'm thinking CUDA ?) – Alex Jul 09 '12 at 12:45
  • I don't know exactly what is XNA, but if it replaces WPF, we cannot, we need to stay in WPF... – mlemay Jul 09 '12 at 12:48

3 Answers3

2

So I searched a bit on that. One Application can create a different Window or Page in a different thread : piece of code taken from here

  private void OnCreateNewWindow(
  object sender,
  RoutedEventArgs e)
  {
    Thread thread = new Thread(() =>
    {
      Window1 w = new Window1();
      w.Show();

      w.Closed += (sender2, e2) =>
      w.Dispatcher.InvokeShutdown();

      System.Windows.Threading.Dispatcher.Run();
    });

   thread.SetApartmentState(ApartmentState.STA);
   thread.Start();
  }

So that was the good news. But in your case that doesn't really apply, since you have one Window, and I tried this it doesn't really work :

     private void OnCreateNewWindow(object sender, RoutedEventArgs e)
     {
       SynchronizationContext syncContext = SynchronizationContext.Current;
       var btn = sender as Button;
       var st = btn.Parent as StackPanel;

       Thread thread = new Thread(() =>
         {
            Button button = new Button();
            syncContext.Post(delegate { st.Children.Add(button) ;}, null); //Exception here
         });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
     }

I tried to create a separate control in a different thread, which works, but then when I try to add it to the stackPanel it fails with the InvalidOperationException

I know it doesn't directly answer you question, but I least you know that all controls in the same Window must belong to the same thread.

MBen
  • 3,956
  • 21
  • 25
1

It sounds like you need to be using virtualization more than anything else. The user can only see a small part of the virtual workspace at any time, so you should only be refreshing that part.

Other than that, have you profiled? What is it exactly pegging your CPU?

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • The user can see all parts at the same time when he is zoomed out. Yes I have profiled, the render process takes the major CPU work – mlemay Jul 09 '12 at 12:12
  • Why can't you push the zooming logic to the server? ie. the client only ever receives images the size of the window. The client asks the server for an image of that size with a specified zoom level and zoom point. So as the user moves around, you're just asking the server for a single, smaller image. – Kent Boogaart Jul 09 '12 at 12:47
  • It's not just an image... our controls needs to works while I'm zooming or panning, and what is killing the CPU is when it render the given image... – mlemay Jul 09 '12 at 12:52
0

I would 'fake' those controls and paint them ones into a background when zooming. You could even draw small images that looks like the controls. You can speed up the zooming, when using a smaller (scaled) background. Then when ready, i cannot imagen that 2k controls need to be used at the same time, so only repaint or add the controls that can be seen/operated. Calculating the x,y of every control and check if they are present in the viewrectangle and drawing them, is a lot faster than drawing them all.

Most of the spectactular graphics are done with these kind of tricks.

Jeroen
  • 449
  • 4
  • 2