I am working on a paint like application in wpf.I want the users to be able to add some drawings over images or plain surfaces.Also i want to draw some basic shapes like line,ellipse or a rectangle.I am trying to work with an inkcanvas,where i can do freehand drawing,but i cant draw shapes like in paint.Can anyone guide me and provide some clues on how to do it.Please help me on this.Any inputs will be greatly appreciated.
There are two sorts of collections in an InkCanvas:
Strokes, which are composed of StylusPoints and defined by DrawingAttributes. That's what the Ink is, as drawn by a mouse or stylus.
The other is Children, which can contain FrameworkElements. Ellipse, for instance, is a Shape is a FrameworkElement.
Try playing around with yourCanvas.Children.Add(ellipse) and see how you go. There is certainly no reason to shy away from the InkCanvas just because you also want to use predefined shapes.
It's worth pointing out, though, that the InkCanvas's little brother, the InkPresenter, does NOT have a Children property. And Silverlight only has that one.
WPF provides a Shape class that includes prebuilt methods that you can draw shapes with. Don't use the inkcanvas and instead draw directly to a canvas.
Here http://ciintelligence.blogspot.com/2011/07/silverlight-drawing-tool-silver-draw.html
you can find better control which improved SilverDraw control with extra features:
Freatures are:
* You can draw basic shapes and also can draw using freehand pencil.
* You can erase drawing.
* You can undo and redo drawing.
* Can save drawing as jpeg in server side.
Here is a simple implementation:
public void drawCircleAp(Double EHeight, Double EWidth, InkCanvas surface)
{
Ellipse e1 = new Ellipse();
e1.Width = EWidth;
e1.Height = EHeight;
var brush = new SolidColorBrush();
brush.Color = Color.FromArgb(100, 0, 0, 0);
e1.Stroke = brush;
e1.StrokeThickness = 4;
surface.Children.Add(e1);
}
Related
I am new in WPF. I am upgrading a software in which I have to draw a map road sketch, i already have the input values:
objdraw.Circle (CentreX, CentreY), radius, RGB(255, 0, 0), StartAngle, EndAngle, 1
I want to know if there is a way to use the same values but with the new drawing shapes in VB.NET.
I really appreciate any help with this.
Thanks!
If you're using WPF, there is a class called System.Windows.Shapes.Ellipse.
Note that you don't quite "draw" with this. Instead, it's just another control that you would put into a panel. That control has properties to control things like it's position, size, stroke thickness, etc.
For general information on drawing in WPF, see the overview of drawing objects on MSDN.
this is my fist question here,
but I didn't find a real answer to my question.
I work on a visualization program and use C# and WPF.
I need to draw a treemap. I actually create Rectangle objects and then add them to the Canvas which works really nice and is very useful, since I also add event handlers to those rectangles (mouse click).
I have a problem with the performance though.
When I add the rectangles and set the Stroke property (SolidColorBrush) the whole process is slowing down extremely. Without those strokes set the speed is ok.
I already improved the performance a little by adding Rectangle objects to a newly created Canvas object and then adding this new Canvas object to the original Canvas object (so not all rectangles are direkt children of the original Canvas, which should help speeding things up).
So my question is how it is possible to add a Stroke to all those Rectangles without breaking the speed.
You can find a comparison of the 'strokeless' and 'stroked' treemap versions in the links.
Treemap without Strokes
Treemap with Strokes
Thank you very much for your help!
edit:
Ok, I have found a solution!
Sorry for writing here first, but I already searched for hours to find a solution but now I found out tht the problem was my used SolidColorBrush!
I have something like this:
public static SolidColorBrush TreeMapBorderBrush;
And I use this Brush to set the Stroke property of every Rectangle that should be added to the Canvas. But exactly that was the problem.
The code looked like this before:
rect.Stroke = Visualization_Helper.TreeMapBorderBrush;
I changed it to this now:
rect.Stroke = Visualization_Helper.TreeMapBorderBrush.Clone();
So I only work with a copy of that Brush on each Rectangle now, which speeds up the processing like there was no Stroke (like in my question)!
Just for your information! Weird!
I have to draw a lot of Shape (about 1/2 hundred thousand) as [Canvas][2]'s childrens. I make this in my WPF application dividing work in two parts: first thing I create shapes by setting the properties of each of them (like Margin, Fill, Width, etc...), after I add shapes as Canvas's children.
MyCanvas.Children.Add(MyShape)
Now i want to improve the performance of the second part, because when i draw the shapes my application is blocked for a long period of time. So i tried to use the Dispatcher and its method [BeginInvoke][4] with different [priorities][5]: only if I use the Background priority the main application does not block, otherwise the application remains blocked and the "picture" is not displayed until all shapes are added to my Canvas, but if I use the Background priority obviously everything is slower. I also tried to create a new thread instead of using the Dispatcher, but there was no significant change.
How can I fix this problem, and generally improve the performance of my application when I add my shapes to Canvas?
Thanks.
Need to use Visual objects instead of Shape; in particular, as suggested, DrawingVisual: a visual object that can be used to render vector graphics. In fact, as written in the MSDN library:
DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout, input, focus, or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.
So, for example, to create a DrawingVisual that contains a rectangle:
private DrawingVisual CreateDrawingVisualRectangle()
{
DrawingVisual drawingVisual = new DrawingVisual();
// Retrieve the DrawingContext in order to create new drawing content.
DrawingContext drawingContext = drawingVisual.RenderOpen();
// Create a rectangle and draw it in the DrawingContext.
Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);
// Persist the drawing content.
drawingContext.Close();
return drawingVisual;
}
In order to use DrawingVisual objects, you need to create a host container for the objects. The host container object must derive from the FrameworkElement class, which provides the layout and event handling support that the DrawingVisual class lacks. When you create a host container object for visual objects, you need to store the visual object references in a VisualCollection.
public class MyVisualHost : FrameworkElement
{
// Create a collection of child visual objects.
private VisualCollection _children;
public MyVisualHost()
{
_children = new VisualCollection(this);
_children.Add(CreateDrawingVisualRectangle());
// Add the event handler for MouseLeftButtonUp.
this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
}
}
The event handling routine can then implement hit testing by invoking the HitTest method. The method's HitTestResultCallback parameter refers to a user-defined procedure that you can use to determine the resulting action of a hit test.
Agreed that if you want to draw millions of elements, you simply can't do it in WPF. WriteableBitmapEx as mentioned is a good alternative.
See this related question which goes into depth on high performance graphics in WPF and the alternatives available.
If you simply must use Canvas, check out this ZoomableApplication2 - A million items. This is a Canvas based demo which makes heavy use of Virtualization to get reasonable performance with 1,000,000 UIElements on a Canvas.
That's a lot of UIElements and probably isn't going to give the kind of performance you're looking for. Do you need to be able to interact with each of the elements you're rendering? If not, I would highly recommend looking into using WriteableBitmap instead. If you need to draw shapes and don't want to create all that logic yourself (who would want to?), check out the WriteableBitmapEx project over on CodePlex.
This may be somewhat unrelated, and I apologize if you feel this way, but in the hopes that it can shed some light for other users, I'll share this tidbit.
We had some performance issues with a Canvas control used for capturing signatures. The capture was very jagged, and we couldn't draw curved lines as a result. It turned out to be related to a style was was generating drop-shadows on the UI elements. Disabling the drop-shadow effect solved our problem.
I need to draw a pushpin for the Bing Silverlight control that can have the head be a variable color. I can draw a nice dot like this:
Dim marker As Ellipse = New Ellipse
marker.Fill = New SolidColorBrush(Color.FromArgb(255, 11, 255, 0))
marker.Stroke = New SolidColorBrush(Colors.Gray)
marker.Width = 10
marker.Height = 10
I'll be making dozens of pushpins, each with a slightly different color for the Fill. How can I add the pointy part? I would like to have some amount of flaring out at the top so that it looks more like a pushpin and less like a lollipop.
Examples in C# are welcome as well.
Maybe there's a reason you need it to be a custom one rather than using the built-in pushpin objects, but if not, you can set the background color on those pushpins like so:
myPushpin.Background = new SolidColorBrush(Colors.Gray);
As far as actually drawing your own, I'm not as sure. Could you draw some sort of a triangle?
We use Windows Forms and custom user controls, and I would like to be able to rotate the panel hosting the userControl in a particular form. I have seen similar functionnalities with WPF, but I can't use it for the moment. Is it possible to achieve the rotation of a panel and its children using possibly built-in .NET methods or GDI+?
I have seen some pretty cool visual effect with menus that are displayed in game development, so I was wondering if it would be possible to create similar effects using Windows Forms.
Rotating a panel and its children in Windows Forms is not something directly supported, and I think it will end up being a buggy headache that could easily suck up lots of time. It's especially painful to think about when you could do this in WPF with zero lines of C# code and only a tiny bit of XAML.
You can use rotations in GDI+ by calling the RotateTransform method on a Graphics object.
However, rotating an entire control is not so simple, and will depend heavily on how the control is implemented.
If it's a composite UserControl that has other controls inside of it, you're out of luck.
If it's a sinlge control that paints itself, try inheriting the control, overriding the OnPaint method, and calling RotateTransform on the Graphics object. However, you will probably have trouble with it. In particular, you will probably need to override all of the mouse events and call the base control's events with rotated coordinates.
You can get halfway there by calling the DrawToBitmap method on your panel, then rotating the bitmap and displaying it e.g. in a PictureBox:
var bitmap = new Bitmap(panel.Width, panel.Height);
panel.DrawToBitmap(bitmap, new Rectangle(Point.Empty, panel.Size));
bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
var pictureBox = new PictureBox();
pictureBox.Location = panel.Location;
pictureBox.SizeMode = PictureBoxSizeMode.AutoSize;
pictureBox.Image = bitmap;
Controls.Remove(panel);
Controls.Add(pictureBox);
Rotation angles other than 90-degree increments are also possible, if you draw the bitmap into another bitmap using GDI:
var bitmap2 = new Bitmap(bmp.Width + 75, bmp.Height + 100);
var graphics = Graphics.FromImage(bmp2);
graphics.TranslateTransform(bitmap2.Width / 2, bitmap2.Height / 2);
graphics.RotateTransform(-15f);
graphics.TranslateTransform(-bitmap.Width / 2, -bitmap.Height / 2);
graphics.DrawImageUnscaled(bitmap, Point.Empty);
graphics.Dispose();
The problem of course is that you're only displaying an image of your panel, and not the panel itself, so it's no longer possible to interact with the controls inside.
That could probably be done as well, but you would have to mess with window messages, which gets quite a bit more complicated. Depending on your needs you might also be able to get away with handling click and key events on the PictureBox, manipulating the controls in the panel, and then updating the image.