A suggested (simple) approach for drawing a lot of visuals in WPF?
I'm writing an interface that has a large (~ 50,000 pixels wide) "canvas" area that is used to display a lot of data in a fairly new way. This is due to a lot of lines, rectangles and text. The user can scroll to explore the entire canvas.
Right now I'm just using a standard Canvas panel with various Shapes placed on it. It's nice and easy to do: build a shape, assign some coordinates, and attach it to the canvas. Unfortunately, it is quite slow (for creating children, not for actual rendering).
I've looked at a few alternatives , it's a little intimidating. I don't need anything fancy - just the ability to efficiently construct and place objects in the coordinate plane. If all I get are lines, colored rectangles, and text, then I'll be happy.
Do I need Geometry
instances inside Geometry Group
inside GeometryDrawing
inside some container Panel
?
Note. I would like to include text and graphics (i.e. colored rectangles) in the same space if possible.
a source to share
Try not to create forms you don't need and recycle the ones you already have. Basically, no user will see the entire screen, so they should NOT have forms that are hidden from view. Don't create new ones that you can avoid - basically save the shapes in a "ready-made" list so you can reuse them.
a source to share
If you have a large number of Shape instances, you can build them asynchronously (on a worker thread) and enqueue the actual add operations through the dispatcher. The idea here is that the UI won't be complete right away, but the user can start interacting right away and the elements keep loading.
EDIT: The above is not correct. WPF requires Visual elements to be created on the UI thread. You can perform this "lazy" visual loading using a template like this:
private Random _random = new Random();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Thread testThread = new Thread(TestThread);
testThread.Start();
}
private void TestThread()
{
for (int i = 0; i < 1000; i++)
{
Dispatcher.BeginInvoke((Action)CreateShape);
}
}
private void CreateShape()
{
var shape = new Rectangle();
shape.Width = _random.Next(10, 50);
shape.Height = _random.Next(10, 50);
shape.Fill = new SolidColorBrush(Colors.Red);
Canvas.SetLeft(shape, _random.Next(0, 400));
Canvas.SetTop(shape, _random.Next(0, 200));
LayoutRoot.Children.Add(shape);
}
This basically suspends tasks that will run "asynchronously" on the UI thread (that is, whenever the message pump is serviced), so you can maintain responsiveness while doing a "long" UI update.
a source to share