Creating and Accessing a GeometryGroup in CodeBehind - c#

i'm new in the StackOverflow Community and please excuse my bad english, i try to imrpove it.
I am using your help for my bachelorthesis and you helped me already a lot, thanks. I am writing a tool to visualize data in wireless networks.
I add a GeometryGroup to my Canvas to connect some of my CustomControls with a line. The line is being updated, when the control is moved etc. I've used the following article: https://denisvuyka.wordpress.com/2007/10/21/wpf-diagramming-drawing-a-connection-line-between-two-elements-with-mouse/ to make it work.
This is the code i use in my XAML.
<Path Name="myPath" Stroke="#FF132FE0" StrokeThickness="1">
<Path.Data>
<GeometryGroup x:Name="connectors"/>
</Path.Data>
</Path>
What i am trying to do is to create my own canvas class and add the GeometryGroup in the code behind. What i tried to do was:
System.Windows.Shapes.Path pathGroup= new System.Windows.Shapes.Path();
BrushConverter bc = new BrushConverter();
Brush Brush = (Brush)bc.ConvertFrom("#FF132FE0");
cmp.Stroke = Brush;
cmp.StrokeThickness = 1;
GeometryGroup connectors= new GeometryGroup();
pathGroup.Data=connectors;
My Problem is, that it didn't workt as intended. With the XAML implementation i can just use the following:
connectors.Children.Add(obj);
I try to to sum up my problem. I would like to create with c#-code a GeometryGroup to be able to add and remove lines, whenever i want it.
Thank you =)

You might want to have a derived Canvas with a connectors field (similar to the one created from the XAML shown in your question).
The Canvas would draw the connectors by means of an overridden OnRender method like shown below.
public class CustomCanvas : Canvas
{
private readonly GeometryGroup connectors = new GeometryGroup();
protected override void OnRender(DrawingContext dc)
{
var stroke = new SolidColorBrush(Color.FromRgb(0x13, 0x2F, 0xE0));
dc.DrawGeometry(null, new Pen(stroke, 1), connectors);
base.OnRender(dc);
}
}
Some additional code in another method of the derived Canvas class would now add or remove Geometry objects to/from the Children collection of the connectors object.
You might of course also want to declare properties for the connector's Stroke, StrokeThickness, etc.

Related

How do I reference a rectangle created programmatically, with XAML?

I am working with WPF for the first time. I am creating a rectangle object & adding it as a child of a canvas.
How do I reference it in XAML?
I want to be able to rotate it over time but don't know how to access it from the MainWindow.xaml code...
I haven't been able to find an answer to this anywhere (maybe you can't do it this way?)
Edit:
I tried setting the Name property of the rectangle to Test (in C# code) and then doing
<Rectangle x:Name="Test">
<Rectangle.LayoutTransform>
<RotateTransform Angle="-45"/>
</Rectangle.LayoutTransform>
</Rectangle>
(This didn't work)
If you create a control in C#, you cannot access it in XAML. I think you must create the necessary animation in C# too.
Applying your rotation in C# could look like this:
var rect = new Rectangle();
rect.LayoutTransform = new RotateTransform() { Angle = -45 };
parentPanel.Children.Add(rect);
The better way would be to generate the Rectangle in XAML and apply there the animation. But this depends on your exact situation. e.g. you can create a single Rectangle in XAML and use this one or you can bind an ItemsControl and create a Rectangle in the ItemTemplate for each entry in the binded list.

How to make a UserControls BackColor transparent in C#?

I created a simple stick man in a Windows Form User-Control (consisting of a radio button and three labels and one progress bar).
I set the back-color of the new user-control to transparent so that when I drag it onto my form, it blends with other colors and drawings on the form.
I am not getting what I'm trying to achieve.
Here is the picture:
UserControl already supports this, its ControlStyles.SupportsTransparentBackColor style flag is already turned on. All you have to do is set the BackColor property to Color.Transparent.
Next thing you have to keep in mind in that this transparency is simulated, it is done by asking the Parent of the control to draw itself to produce the background. So what is important is that you get the Parent set correctly. That's a bit tricky to do if the parent is not a container control. Like a PictureBox. The designer will make the Form the parent so you will see the form's background, not the picture box. You'll need to fix that in code, edit the form constructor and make it look similar to this:
var pos = this.PointToScreen(userControl11.Location);
userControl11.Parent = pictureBox1;
userControl11.Location = pictureBox1.PointToClient(pos);
In constructor set style of control to support a transparent backcolor
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
and then set Background to transperent color
this.BackColor = Color.Transparent;
From MSDN
A more complex approach (and possibly working one) is described here - with overrding of CreateParams and OnPaint.
Why all those things?
UserControl class has property Region.
Set this to what ever shape you like and no other adjustments are needed.
public partial class TranspBackground : UserControl
{
public TranspBackground()
{
InitializeComponent();
}
GraphicsPath GrPath
{
get
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(this.ClientRectangle);
return grPath;
}
}
protected override void OnPaint(PaintEventArgs e)
{
// set the region property to the desired path like this
this.Region = new System.Drawing.Region(GrPath);
// other drawing goes here
e.Graphics.FillEllipse(new SolidBrush(ForeColor), ClientRectangle);
}
}
The result is as in the image below:
No low level code, no tweaking, simple and clean.
There is however one issue but in most cases it can go undetected, the edges are not smooth and anti-aliasing will not help either.
But the workaround is fairly easy. In fact much easier than all those complex background handling..

Drawing to a brush

I have made a control which inherits TextBox, and I'm trying to give a notebook grid:
I already have the code that will specify where to draw the lines including all of the grids features, but I'm not sure what to draw it to.
I've Googled a lot and searched for a brush that will let me have the same interface as a DrawingContext (so I could call drawingContext.DrawLine() etc.), or something familiar, but I couldn't find any!
So how can I achieve to get my grid background?
P.S I can't create a static bmp file and load it, because the grid color and spacing would most certainly change
You could try using DrawingVisual to get your DrawingContext then create a VisualBrush to assign to your Background. Something like this.
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawLine( new Pen(Brushes.Red,5),new Point(0,0),new Point(50,50));
dc.Close();
VisualBrush vb = new VisualBrush(dv);
textBox1.Background = vb;
You can intercept the Paint event for your control. You get a PaintEventArgs argument, which includes a ClipRectangle and a Graphics object.
Check out Control.Paint Event.
Once you have your Graphics object, you can call DrawLine and FillRectangle on it directly.
You're looking to make a custom-drawn control. You'll want to override the OnPaint method of your control class and draw the background in that method. Here's an example on how to do it: http://msdn.microsoft.com/en-us/library/b818z6z6(v=vs.90).aspx
To draw your background, grab the drawing context and draw your background after first calling the base OnPaint method:
protected override void OnPaint(PaintEventArgs pe)
{
// Call the OnPaint method of the base class.
base.OnPaint(pe);
// Declare and instantiate a new pen.
System.Drawing.Pen myPen = new System.Drawing.Pen(Color.Aqua);
// Draw an aqua rectangle in the rectangle represented by the control.
pe.Graphics.DrawRectangle(myPen, new Rectangle(this.Location, this.Size));
}
EDIT:
Since you're using WPF, you can take a look here to see a full example on custom designs: WPF .NET 3.5 Drawing Customized Controls and Custom UI Elements

Using OutlineTextControl

I am using the OutlineTextControl that I found linked here somewhere and its great, however the outline gets drawn on the text instead of outside the text (like an outline). Is there any way to modify the class to do what I need?
Link to control code:
http://blogs.msdn.com/b/wpfsdk/archive/2006/12/24/using-text-as-a-decorative-graphic.aspx
Maybe there is an alternative way to do sharp outlines on text?
**Edit
I modified the class to draw the outline separately as below, and created a private variable in the class to hold my formatted text. This works almost perfect, the N letter has a little sharp point above it, and the W has a sharp point below as shown in my image, what would cause this?
drawingContext.DrawGeometry(null, new Pen(Stroker, StrokeThickness), _textGeometry);
drawingContext.DrawText(_formattedText, new Point(0, 0));
****Edit 2
Added the following code above the drawing code to define my stroke pen:
Pen pop = new Pen(Stroker, StrokeThickness);
pop.LineJoin = PenLineJoin.Round;
pop.MiterLimit = 10;
Now my outline is smooth and exactly what I wanted:
Added the following code above the drawing code to define my stroke pen:
Pen pop = new Pen(Stroker, StrokeThickness);
pop.LineJoin = PenLineJoin.Round;
pop.MiterLimit = 10;
Now my outline is smooth and exactly what I wanted:

How do draw FormattedText (if not in the onRender method)

I draw some Ellipse and add them to a Grid.
Then I'd like to add some FormattedText to each Ellipse. This i could do by getting the RectangleBounds of the Ellipse.
But following this example:
http://msdn.microsoft.com/en-us/library/bb613560.aspx#FormattedText_Object
I need a DrawingContext to draw the text. But if I don't wantto override onRender, how can I get a DrawingContext?
You can use a DrawingGroup instead. It has an Open method that returns a DrawingContext and you can use that to construct a drawing.
You'll then need to arrange for that drawing to appear in the UI somehow. The easiest way is to wrap it in a DrawingBrush and use that to paint some existing element in the UI. For example, if you've got an ellipse called myEllipse, this will set its Fill property to be a DrawingBrush based on a DrawingGroup that contains a single bit of FormattedText:
var drawing = new DrawingGroup();
using (var context = drawing.Open())
{
var text = new FormattedText("This is some text",
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Calibri"),
30,
Brushes.Green);
context.DrawText(text, new Point(0, 0));
}
var db = new DrawingBrush(drawing);
db.Stretch = Stretch.None;
myEllipse.Fill = db;
If you've already filled the Ellipse with something else, you have two choices. You could either add more content to this drawing - you can make as many calls into the context as you like. For example, if I add this immediately before the call to context.DrawText:
context.DrawRectangle(Brushes.Cyan, null, new Rect(0, 0, 300, 100));
I'll get a cyan background behind the text. (You'd need to adjust the coordinates in these examples to suit your layout, of course.)
But it's probably simpler to add an extra element to host the drawing, rather than trying to piggy-back it into an element that's there to do something else. So you could put a Rectangle element positioned directly over the Ellipse, and use a DrawingBrush such as this as the Fill for that Rectangle. The Rectangle won't actually look rectangular, because this DrawingBrush doesn't paint in its whole area. So the effect will look much the same as it would if you'd layered a TextBlock over an Ellipse.

Categories

Resources