I have a drawing visual which I have drawings, how do I add this to my canvas and display?
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(0, 0), new System.Windows.Size(100, 100));
drawingContext.DrawRectangle(System.Windows.Media.Brushes.Aqua, (System.Windows.Media.Pen)null, rect);
// Persist the drawing content.
drawingContext.Close();
How do I add this to a canvas? Suppose I have a Canvas as
Canvas canvas = null;
canvas.Children.Add(drawingVisual); //Doesnt work as UIElement expected.
How do I add my drawingVisual to canvas?
TIA.
You have to implement a host element class, which would have to override the VisualChildrenCount property and the GetVisualChild() method of a derived UIElement or FrameworkElement to return your DrawingVisual.
The most basic implementation could look like this:
public class VisualHost : UIElement
{
public Visual Visual { get; set; }
protected override int VisualChildrenCount
{
get { return Visual != null ? 1 : 0; }
}
protected override Visual GetVisualChild(int index)
{
return Visual;
}
}
Now you would add a Visual to your Canvas like this:
canvas.Children.Add(new VisualHost { Visual = drawingVisual });
Related
I have the following custom Control:
public class Line : Control
{
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var p = new Pen(Color.Black, 3))
{
var point1 = new Point(234, 118);
var point2 = new Point(293, 228);
e.Graphics.DrawLine(p, point1, point2);
}
}
}
And a Form where I add as new control a new instance of the Line class:
Controls.Add(new Line());
The problem is that the method OnPaint isn't called and no line is drawn. Why? How can i fix it?
Your are not giving it a Size, try creating a Constructor and setting a default size there, you also seem to be using the parent controls coordinates, I would use the location of the Usercontrol to set your start position and only be concerned with the Width and Height of the control needed to contain your line.
public Line()
{
Size = new Size(500, 500);
}
In my wpf application i am drawing a lot of geometries as below. My requirement is to change the color of drawingvisual with out redrawing it? any possibilities in wpf?
using (DrawingContext vDrawingContext = vDrawingVisual.RenderOpen())
{
StreamGeometry vGeom = GetCutGeometry(mLength, mWidth);
vDrawingContext.DrawGeometry(mBackGroundBrush, ForeGroundPen, vGeom);
vDrawingContext.Close();
VisualChildren.Add(vDrawingVisual);
}
How could be mBackGroundBrush dyamic colors?
Provided that mBackGroundBrush is a modifiable SolidColorBrush (i.e. it is created in your application and none of the predefined brushes), you could simply change its Color property. That will change the fill color of each drawn geometry with redrawing.
private SolidColorBrush mBackGroundBrush = new SolidColorBrush(Colors.Black);
...
mBackGroundBrush.Color = Colors.Red;
or
mBackGroundBrush.Color = Color.FromArgb(255, 255, 0, 0);
I have done one work around as below. seems working.
///Kept as arefrence while initial drawing phase.
private DrawingVisual mDrawingVisual = null;
if (null != mDrawingVisual)
{
using (DrawingContext vDrawingContext = mDrawingVisual.RenderOpen())
{
DrawingGroup vDrawingGroup = VisualTreeHelper.GetDrawing(mDrawingVisual);
if (null != vDrawingGroup)
{
foreach (Drawing vDrawing in vDrawingGroup.Children)
{
GeometryDrawing vGeometryDrawing = vDrawing as GeometryDrawing;
if (null != vGeometryDrawing)
{
vGeometryDrawing.Brush = mBackGroundBrush;
}
}
}
vDrawingContext.DrawDrawing(vDrawingGroup);
vDrawingContext.Close();
}
}
My question : How to disable a User Control to draw it's background (or Region)
Note : I already tried to override and empty OnPaintBackground or set background color to transparent.
I'm trying to bypass winform paint for my custom user controls in a custom container.
For that I thought to give a try to this : Beginners-Starting-a-2D-Game-with-GDIplus
My setup is :
A Form containing:
A User control (DrawingBoard)
A Container with elements I can drag and drop to this DrawingBoard (it's a listbox).
My render loop is inside the DrawingBoard with all elements specified in the previous link.
public DrawingBoard()
{
InitializeComponent();
//Resize event are ignored
SetStyle(ControlStyles.FixedHeight, true);
SetStyle(ControlStyles.FixedWidth, true);
SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint, true);// True is better
SetStyle(System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, true); // True is better
// Disable the on built PAINT event. We dont need it with a renderloop.
// The form will no longer refresh itself
// we will raise the paint event ourselves from our renderloop.
SetStyle(System.Windows.Forms.ControlStyles.UserPaint, false); // False is better
}
#region GDI+ RENDERING
public Timer t = new Timer();
//This is your BackBuffer, a Bitmap:
Bitmap B_BUFFER = null;
//This is the surface that allows you to draw on your backbuffer bitmap.
Graphics G_BUFFER = null;
//This is the surface you will use to draw your backbuffer to your display.
Graphics G_TARGET = null;
Size DisplaySize = new Size(1120, 630);
bool Antialiasing = false;
const int MS_REDRAW = 32;
public void GDIInit()
{
B_BUFFER = new Bitmap(DisplaySize.Width, DisplaySize.Height);
G_BUFFER = Graphics.FromImage(B_BUFFER); //drawing surface
G_TARGET = CreateGraphics();
// Configure the display (target) graphics for the fastest rendering.
G_TARGET.CompositingMode = CompositingMode.SourceCopy;
G_TARGET.CompositingQuality = CompositingQuality.AssumeLinear;
G_TARGET.SmoothingMode = SmoothingMode.None;
G_TARGET.InterpolationMode = InterpolationMode.NearestNeighbor;
G_TARGET.TextRenderingHint = TextRenderingHint.SystemDefault;
G_TARGET.PixelOffsetMode = PixelOffsetMode.HighSpeed;
// Configure the backbuffer's drawing surface for optimal rendering with optional
// antialiasing for Text and Polygon Shapes
//Antialiasing is a boolean that tells us weather to enable antialiasing.
//It is declared somewhere else
if (Antialiasing)
{
G_BUFFER.SmoothingMode = SmoothingMode.AntiAlias;
G_BUFFER.TextRenderingHint = TextRenderingHint.AntiAlias;
}
else
{
// No Text or Polygon smoothing is applied by default
G_BUFFER.CompositingMode = CompositingMode.SourceOver;
G_BUFFER.CompositingQuality = CompositingQuality.HighSpeed;
G_BUFFER.InterpolationMode = InterpolationMode.Low;
G_BUFFER.PixelOffsetMode = PixelOffsetMode.Half;
}
t.Tick += RenderingLoop;
t.Interval = MS_REDRAW;
t.Start();
}
void RenderingLoop(object sender, EventArgs e)
{
try
{
G_BUFFER.Clear(Color.DarkSlateGray);
UIPaint(G_BUFFER);
G_TARGET.DrawImageUnscaled(B_BUFFER, 0, 0);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
#endregion
Then my elements get the event fired and try to draw what I would like:
public override void UIPaint(Graphics g)
{
Pen p = new Pen(Color.Blue,4);
p.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
g.DrawLines(p, new Point[] { new Point(Location.X, Location.Y), new Point(Location.X + Width, Location.Y), new Point(Location.X + Width, Location.Y + Height), new Point(Location.X, Location.Y + Height), new Point(Location.X, Location.Y - 2) });
g.DrawImageUnscaled(GDATA.GetWindowImage(), Location);
}
here is what happening on my DrawingBoard :
As I can't post image ... here is the link : http://s8.postimage.org/iqpxtaoht/Winform.jpg
The background is DarkSlateGray because my G_BUFFER state to clear each tick with that, Ok
The blue rectangle is what I paint, but it get cropped, KO
The Texture is cropped, KO
The region that crop my drawing is the control size.
So from there I've tried everything I could to disable WinForm to make some magic drawing in background. Tried to override and empty everything that got paint/update/refresh/invalidate/validate on Form/DrawingBoard/Elements but nothing allowed me to get my texture or drawing to not get cropped by the control background : (
I also tried to set the background of the Element as transparent and also to set Form.TransparencyKey = blabla with each element BackColor = blabla. But failed each time.
I'm certainly missing something : / But I don't know what.
Why don't you want to draw the background? To avoid problems with flickering in my custom control (derived from class Control), here's what I did:
(1) override OnPaintBackground:
protected override void OnPaintBackground(PaintEventArgs pevent)
{
}
(2) Draw in an offscreen Bitmap and then transfer it to the screen:
Bitmap _completeFrame;
protected override void OnPaint(PaintEventArgs pe)
{
DrawFrame(); // draws onto _completeFrame, calling new Bitmap()
// when _completeFrame is null or its Size is wrong
var g = pe.Graphics;
g.DrawImage(_completeFrame, new Point());
}
I am having an issue with the BorderThickness or BorderBrush property in Windows 8.
In win7, the code below correctly outlines editControl in a 5px thick read outline, however it does not work in windows 8. I am wondering if there is something deprecated or unsupported in windows 8 now? I cannot find any notion of that on the microsoft documentation.
editControl.BorderThickness = new Thickness(5);
editControl.BorderBrush = Brushes.Red;
Anyone able to help?
I found a workaround using using Adorners.
private class ErrorHighlightAdorner : Adorner
{
public ErrorHighlightAdorner(UIElement adornedElement)
: base(adornedElement)
{
}
protected override void OnRender(DrawingContext drawingContext)
{
Rect sourceRect = new Rect();
FrameworkElement fe = AdornedElement as FrameworkElement;
if (fe != null)
{
sourceRect = new Rect(fe.RenderSize);
}
else
{
sourceRect = new Rect(AdornedElement.DesiredSize);
}
Pen renderPen = new Pen(new SolidColorBrush(Colors.Red), 2.0);
drawingContext.DrawRectangle(null, renderPen, sourceRect);
}
}
I'm drawing a graph in a WPF application, but lines drawn using drawingContext.DrawLine(...) are drawn to sub-pixel boundaries.
I'm able to get them to look nice by creating Line objects, but I don't want to create tens of thousands of those every time the visual is invalidated.
How can I force them to fit to pixels?
You may draw the lines into a derived DrawingVisual that has the protected VisualEdgeMode property set to EdgeMode.Aliased:
public class MyDrawingVisual : DrawingVisual
{
public MyDrawingVisual()
{
VisualEdgeMode = EdgeMode.Aliased;
}
}
public class DrawingComponent : FrameworkElement
{
private DrawingVisual visual = new MyDrawingVisual();
public DrawingComponent()
{
AddVisualChild(visual);
using (DrawingContext dc = visual.RenderOpen())
{
dc.DrawLine(new Pen(Brushes.Black, 1d), new Point(100, 100), new Point(100, 200));
dc.DrawLine(new Pen(Brushes.Black, 1d), new Point(105.5, 100), new Point(105.5, 200));
dc.DrawLine(new Pen(Brushes.Black, 1d), new Point(112, 100), new Point(112, 200));
}
}
protected override int VisualChildrenCount
{
get { return 1; }
}
protected override Visual GetVisualChild(int index)
{
return visual;
}
}
Strange enough, but calling RenderOptions.SetEdgeMode(visual, EdgeMode.Aliased) on a non-derived DrawingVisual doesn't do the job.
That's great.
Another option (more complicated in that case) is using RenderOptions.SetEdgeMode on a DrawingGroup:
https://stackoverflow.com/a/16984921/2463642