I'm creating a Path in Silverlight, and adding elements to it on mouse events. But, although the elements are there in memory, the screen doesn't get updated until something else causes a screen repaint to happen.
Here's the relevant code - I'm responding to a mouse event, and I keep a class member of the path I'm editing.
Path path = null;
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point thisPoint = e.GetPosition(LayoutRoot);
if (path == null)
{
CreateNewPath(thisPoint);
path.LayoutUpdated += new EventHandler(path_LayoutUpdated);
}
else
{
path.AddLineElement(thisPoint);
}
}
private void CreateNewPath(Point startPoint)
{
path = new Path();
PathGeometry geometry = new PathGeometry();
path.Data = geometry;
PathFigureCollection figures = new PathFigureCollection();
geometry.Figures = figures;
PathFigure figure = new PathFigure();
figures.Add(figure);
figure.StartPoint = startPoint;
figure.Segments = new PathSegmentCollection();
path.Stroke = new SolidColorBrush(Colors.Red);
path.StrokeThickness = 2;
path.Stretch = Stretch.None;
LayoutRoot.Children.Add(path);
}
AddLineElement
is an extension method for the path class just to simplify:
public static class PathHelper
{
public static void AddLineElement(this Path thePath, Point newPoint)
{
PathGeometry geometry = thePath.Data as PathGeometry;
geometry.Figures[0].Segments.Add(new LineSegment { Point = newPoint });
}
}
This is the minimum needed to reproduce the problem. If you run this code in a full WPF app it all works as expected. Mouse clicks add line elements which appear immediately. However, in Silverlight it's a different matter. The clicks appear to do nothing, even though stepping through the code shows that the data is getting added. But if you click a few times, then resize the browser, for example, the path elements appear. If you happen to have a button on the page as well, and move the mouse over, the path will appear.
I've tried all the obvious things, like calling InvalidateMeasure and InvalidateArrange on the Path (and on the parent grid) to no avail.
The only workaround I've got is to change a property on the path then change it back, which seems to be enough to get the rendering engine to draw the new path elements. I use Opacity. You have to set it to a different value, otherwise (I presume) the PropertyChanged event won't fire. It's a kludge, though.
Has anyone else played with paths in this way? I guess if I were putting other graphical elements on screen at the same time this wouldn't be an issue, so it's probably not something which will affect may people, but it would be good to know if there's a more correct way to do it.