oerpli
oerpli

Reputation: 340

WPF performance when updating elements

I am currently developing a GUI for an Ising model (german wikipedia because only the picture on the right really matters) which should consist of approx 200x200 spin elements. I implemented this in the following way:

<UniformGrid Name="grid" .... />

and added a rectangle for every spin in the code behind which I update if the value of the spin changes. This somehow was very slow and I changed it so it uses Binding

 <ItemsControl Name="IsingLattice" ItemsSource="{Binding Spins}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Name="grid" ...
            ...
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Rectangle Fill={Binding Color} ...

but this is again - very slow. I tried to debug and improve it for 3 days now but no success so far.

Now the question is: Is my approach wrong? What should I use instead if so? If not - how could I improve the performance?

If it's relevant I will update this post with some details of the implementation of my model.

Edit: It should be possible to change single spins by interacting with the elements. This could be done with a transparent layer on top of the actual graphics though so maybe not that hard anyway.

Upvotes: 4

Views: 2855

Answers (4)

Liero
Liero

Reputation: 27338

ItemsControl is meant to repeat UI controls based on datasource. UI control must be customizable, responsive when layout changes, and interactive. Neither of this is your case. You actualy want to render just a picture.

This - seems to be a Bitmap, so you should threat it as a Bitmap. Instead of ItemsControl use Image and instead of ItemsSource use WritableBitmap as a Source of Image.

When it comes to your original code, it could have couple of performance bottlenecks:

  1. Generation of your classes you used as a ItemsSource can take some time
  2. UniformGrid needs to measure size and calculate position of each element. This can take a while. With Canvas you could achieve better results
  3. It can take some time to ItemsControl to generate 40 000 items from DataTemplate. You could create those rectangles manualy and add it to canvas in code behind
  4. Binding have performance cost. If each of your item is databound, then your binding needs to be evaluated 40 000 times. Instead of binding you could set the properties manualy in code behind.

Using canvas and no binding I was able to render the grid in just 500miliseconds. However, using WritableBitmap or other "pixel based" approach you could display much larger grids.

Upvotes: 4

Bradley Uffner
Bradley Uffner

Reputation: 16991

Have you considered using the BitmapCache to improve rendering speed?

My understanding is that this can significantly improve rendering speed when drawing complex controls, or when having many instances of the control on screen at the same time. You would want to enable the cache at the grid level, not on each individual spinner.

Upvotes: 0

Steven Rands
Steven Rands

Reputation: 5421

You could write a single custom element (derived from FrameworkElement) that stores the spin data internally then renders the data in one pass by overriding the OnRender method:

public sealed class IsingModel : FrameworkElement
{
    readonly bool[] _spinData = new bool[200 * 200];

    protected override void OnRender(DrawingContext dc)
    {
        // use methods of DrawingContext to draw appropriate
        // filled squares based on stored spin data
    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);

        // work out which "cell" was clicked on and change
        // appropriate spin state value in Boolean array

        InvalidateVisual(); // force OnRender() call
    }
}

This approach should be faster than having several thousand individual elements. How much faster I don't know.

Upvotes: 6

nvoigt
nvoigt

Reputation: 77304

A GUI, any kind of GUI technology, being it WPF or Windows Forms or anything else, is not meant to handle heavy graphics. It's meant to be easy to develop simple graphics.

If you need graphic power (like dynamically updating 40.000 cells) then you need a framework for graphics. Most likely, a gaming framework will do, pick one of your choice.

Alternatively, you could try to emulate it yourself by only binding to a single picture and drawing that picture yourself when a cell changes. Maybe that's enough, you will have to test that.

Upvotes: 0

Related Questions