H
hbrower
I'm trying to understand how to speed up the ui. I have been experimenting
with background processing, but am not getting results that I think I should.
To experiment, I've created a window that contains a bunch of randomly sized
and placed circles. My goal is to be able to resize the window without it
hanging or being sluggish. To reduce the processing in the main thread, I've
created a BackgroundWorker thread to handle as much processing as I can.
Given the design, I believe that the windows sizing shouldn't be affected by
the value of numberOfPoints. I expect the update to be delayed, but the
resizing to be independent; however, that is not what I am getting.
Does anyone have any suggestions?
Also, I found that I was not able to freeze a VisualBrush after setting the
visual. Any suggestions on that?
Here's my sample code:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace FreezeTesting
{
class FreezeTesting
{
}
class DrawingPanel : Canvas
{
class WorkData
{
public Size Size { get; private set; }
public WorkData(Size s)
{
Size = s;
}
}
static Random r = new Random();
const int numberOfPoints = 1000;
bool vis = false;
BackgroundWorker bgworker = new BackgroundWorker();
public DrawingPanel()
{
Background = Brushes.White;
bgworker.WorkerSupportsCancellation = true;
bgworker.WorkerReportsProgress = true;
bgworker.DoWork += new DoWorkEventHandler(bgworker_DoWork);
bgworker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(bgworker_RunWorkerCompleted);
}
void bgworker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == false)
{
VisualBrush vb = e.Result as VisualBrush;
if (vb != null)
{
Background = vb;
}
DrawingBrush db = e.Result as DrawingBrush;
if (db != null)
{
Background = db;
}
}
}
void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = null;
WorkData wd = e.Argument as WorkData;
if (wd != null)
{
if (vis)
{
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
for (int i = 0; i < numberOfPoints; i++)
{
int rad = r.Next(10) + 10;
dc.DrawEllipse(Brushes.Black, null, new
Point(r.NextDouble() * wd.Size.Width, r.NextDouble() * wd.Size.Height), rad,
rad);
if (e.Cancel == true)
return;
}
}
VisualBrush vb = new VisualBrush(dv);
vb.Freeze(); // throws an error... don't understand why
e.Result = vb;
}
else
{
GeometryGroup gg = new GeometryGroup();
for (int i = 0; i < numberOfPoints; i++)
{
int rad = r.Next(10) + 10;
gg.Children.Add(new EllipseGeometry(new
Point(r.NextDouble() * wd.Size.Width, r.NextDouble() * wd.Size.Height), rad,
rad));
if (e.Cancel == true)
return;
}
GeometryDrawing gd = new GeometryDrawing(null, new
Pen(Brushes.Black, 1), gg);
DrawingBrush db = new DrawingBrush();
db.Drawing = gd;
db.Freeze();
e.Result = db;
}
}
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
if (bgworker.IsBusy)
bgworker.CancelAsync();
bgworker.RunWorkerAsync(new WorkData(sizeInfo.NewSize));
}
}
class Win : Window
{
public Win()
{
Content = new DrawingPanel();
}
}
class App : Application
{
[STAThread()]
static void Main()
{
new App();
}
App()
{
Run(new Win());
}
}
}
with background processing, but am not getting results that I think I should.
To experiment, I've created a window that contains a bunch of randomly sized
and placed circles. My goal is to be able to resize the window without it
hanging or being sluggish. To reduce the processing in the main thread, I've
created a BackgroundWorker thread to handle as much processing as I can.
Given the design, I believe that the windows sizing shouldn't be affected by
the value of numberOfPoints. I expect the update to be delayed, but the
resizing to be independent; however, that is not what I am getting.
Does anyone have any suggestions?
Also, I found that I was not able to freeze a VisualBrush after setting the
visual. Any suggestions on that?
Here's my sample code:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace FreezeTesting
{
class FreezeTesting
{
}
class DrawingPanel : Canvas
{
class WorkData
{
public Size Size { get; private set; }
public WorkData(Size s)
{
Size = s;
}
}
static Random r = new Random();
const int numberOfPoints = 1000;
bool vis = false;
BackgroundWorker bgworker = new BackgroundWorker();
public DrawingPanel()
{
Background = Brushes.White;
bgworker.WorkerSupportsCancellation = true;
bgworker.WorkerReportsProgress = true;
bgworker.DoWork += new DoWorkEventHandler(bgworker_DoWork);
bgworker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(bgworker_RunWorkerCompleted);
}
void bgworker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == false)
{
VisualBrush vb = e.Result as VisualBrush;
if (vb != null)
{
Background = vb;
}
DrawingBrush db = e.Result as DrawingBrush;
if (db != null)
{
Background = db;
}
}
}
void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = null;
WorkData wd = e.Argument as WorkData;
if (wd != null)
{
if (vis)
{
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
for (int i = 0; i < numberOfPoints; i++)
{
int rad = r.Next(10) + 10;
dc.DrawEllipse(Brushes.Black, null, new
Point(r.NextDouble() * wd.Size.Width, r.NextDouble() * wd.Size.Height), rad,
rad);
if (e.Cancel == true)
return;
}
}
VisualBrush vb = new VisualBrush(dv);
vb.Freeze(); // throws an error... don't understand why
e.Result = vb;
}
else
{
GeometryGroup gg = new GeometryGroup();
for (int i = 0; i < numberOfPoints; i++)
{
int rad = r.Next(10) + 10;
gg.Children.Add(new EllipseGeometry(new
Point(r.NextDouble() * wd.Size.Width, r.NextDouble() * wd.Size.Height), rad,
rad));
if (e.Cancel == true)
return;
}
GeometryDrawing gd = new GeometryDrawing(null, new
Pen(Brushes.Black, 1), gg);
DrawingBrush db = new DrawingBrush();
db.Drawing = gd;
db.Freeze();
e.Result = db;
}
}
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
if (bgworker.IsBusy)
bgworker.CancelAsync();
bgworker.RunWorkerAsync(new WorkData(sizeInfo.NewSize));
}
}
class Win : Window
{
public Win()
{
Content = new DrawingPanel();
}
}
class App : Application
{
[STAThread()]
static void Main()
{
new App();
}
App()
{
Run(new Win());
}
}
}