Custom WPF EndLineCap, StartLineCap & LineJoin or new attached properties - c#

Just wondering if anyone knows how I would implement additional/custom EndLineCap, StartLineCap & LineJoin attributes?
In short, LineJoin="Round" is what I want but I need both sides of the angle are smooth - instead of just the wider angled side.
Also, instead of just Rounded EndLineCap and StartLineCap I want a ball on each end (for instance, a circle at each end who's diameter is double that of the with of the line).
Instead of adding additional custom items, I might be able to achieve this through attached properties, but I don't know where to start.

I don't believe that it is possible to do what you're asking. Line Caps are implemented at a very low level in WPF where there seems to be little possibility of customisation.
The lowest level Graphics API that WPF exposes is the DrawingContext. This provides methods like DrawLine which take a Pen object to specify how LineCaps should be drawn. Your choice of LineCaps is limited to those exposed in the PenLineCap enum - it doesn't provide a "Custom" option.
Having said all that, it may be possible to emulate custom line caps by modifying the path data in a geometry. This answer may give you some hints.

Related

How to render dynamic data in a custom WPF control, such as a line graph?

I'm working on a LineGraph control which consists many DependencyProperties that affect how the control should display its data. For example, the control contains the following properties to affect its axes:
AxisStroke - Color of the axes.
AxisThickness - Stroke thickness of the axes.
It also contains properties for display numbers & tick marks
VerticalTicks - True/False to indicate whether or not ticks appear along the vertical axis
HorizontalTicks - True/False to indicate whether or not ticks appear along the horizontal axis
VerticalMin - Minimum value on the vertical axis (numeric)
VerticalStep - The distance in between each vertical tick
VerticalMax - Maximum value on the vertical axis (numeric)
HorizontalMin - Minimum value on the horizontal axis (numeric)
HorizontalStep - The distance in between each horizontal tick
HorizontalMax - Maximum value on the horizontal axis (numeric)
And many more properties exist to allow for different line styles on a single graph (LineColor, LineThickness, DataPointShape, and DataPointIcon to name a few).
My goal is to be able to call out my LineGraph in XAML to insert it into a Window. I would like to be able to specify each of these settings inside the XAML as well, and see the new rendered image of the control in the WPF designer.
Now, given there is a lot of geometric shapes to render on the LineGraph, I though using a Canvas would be a good choice to render the data. Unfortunately, when I'm working in XAML, I cannot perform computations for the locations of shapes based on the control's width & height.
And yes, the shapes' locations must be computed because the data points for the graph are dynamic and the tick-related information is dynamic. Not to mention, I would like to display the actual values along each axis of the LineGraph.
So, I thought I might be able to display this control as if I was doing the rendering in C# code. Other windowing frameworks sometimes provide a Render method that can be used for laying out all of the sub-components.
Doing this, however, doesn't seem possible since WPF relies heavily on XAML for the visual appearance of controls. Also, requiring that the WPF designer must display the LineGraph based on the properties and data specified, it doesn't seem like C# code would solve the problem.
I suppose my questions are these:
How can I render data dynamically inside of a WPF control?
Am I able to specify in C# how my control is rendered, allowing the WPF designer to reflect it?
Side Note:
I've done quite a bit of research, but I am only finding information on how to implement more simple types of controls. If you know of any references that contain information on this topic, please feel free to post them in addition to your answers. I will be more than happy to learn how to do this completely.
EDIT:
I've created a graph using Excel to elaborate what the LineGraph control might look like if it has correct data and properties.
I will answer this based on my experience on implementing custom built graphing libraries in WIN32, WinForm, WPF, WinCE, WP8+WinRT, ....and even on a FPGA :)
It's extremely difficult to implement one from scratch. It may seem easy at first but you will run into a lot of "What should I do if this happens?". For example, in your above graph it seems you got a DataPoint # (5,100) it graphs it pretty well. But lets say, I add another DataPoint # (5.000000005, 0). How would you handle that in your code? Would you say that each pixel on the graph represents an exact value on the X-Axis, or does each pixel represent a range of X-Values?
I would recommend that you use an already establish library to do what you want to do unless you need something very specific like lets say you need horizontal cursors on the graph (think Tektronix Oscilloscope) and you need to calculate some values in between the two cursors.. then maybe you need to implement your own custom one or build on top of an open source one.
So, if you are still adamant of creating your own custom control here are answers to your questions.
How can I render data dynamically inside of a WPF control?
You can use a WriteableBitmap and create your own primitive drawing library from that. After you're done rendering, set it as the ImageSource of your control.
Or you can use WriteableBitmapEx which has GDI like drawing functions already implemented for you.
WriteableBitmapEx CodePlex Page, I also think you can just get it from NuGet as well.
You can also use a <Canvas> and add UI elements to that as well.
Am I able to specify in C# how my control is rendered, allowing the WPF designer to reflect it?
This depends on how you create your controls, but yes you can create Properties in your custom control that will appear in the Designer. Allowing you to change it thus updating the display. I would read a lot of tutorials about writing your own custom user control library. They can explain it better than I can in a SO answer. If you implement the properties correctly it should like so.....
Full Size Image: http://i.stack.imgur.com/pmevo.png
After changing the Number of Rows from 15 to 10 and the starting Y offset to -1 (thus moving the graph up and making the rows a lot taller)
Full Size Image: http://i.stack.imgur.com/0RKnA.png

Image OCR - Filtering unwanted data

Basically I'm reading vehicle license plates using tessract OCR, however despite being able to emphasise text easily enough via changing contrast, reducing noise an so on, some 'parts' of the vehicle remain on the image which does cause the OCR to throw bad results.
For example take:
I can change this easily enough, such as:
I'm looking to eliminate the edges off each plate, here's another example:
I could remove the edges using pixel manipulation algorithm, however I don't feel it's the right method, and would cause quite a lot of problems.
I've been using the following application to test various methods such as morphology and eliminating the unwanted data, so far I haven't been successful.
http://www.codeproject.com/KB/GDI-plus/Image_Processing_Lab.aspx
However someone with knowledge of this could use the application on the article above to achieve want I'm trying, so feel free to give it a try.
Thanks
Please try to use stroke width transformation concept.
This concept use to segment text from natural images.....
I already did such an algorithm. I just can say that it works great. The secret is, that you need to know that the light is coming just from one side perhaps. You cannot set the image to "black/white" just by using ONE threshold.
Detect the average luminance of parts of the image and use this luminance calculation to set the threshold for each region.
For example, if the left top is lighter, you need a lower threshold to make these parts not to bright. And if the bottom right has low light, you need to set the threshold higher to receive all existing light information.
Then, you need just to drive into the image from each side by using the method:
IsPixelAboveThreshold ?
If it is below, you are on the border, if it is above, you can say you are on the middle of the image with more brightness.
Regards

WPF: how to create complex user controls? (like GDI+)

For example, let's say I want to create something complex. like a zoommable/pannable graph. like google maps, or a stock market graph or something.
XAML and that whole hierarchy doesn't really work. What I'm trying to do is kind of more like back in the day with GDI+/Winforms. Where I could override paint
i.e., "protected override void OnPaint(PaintEventArgs e)" and then I'd draw whatever the heck I wanted. Where I'd do double buffering. Like draw to a buffer and blip it to the screen.
But how do I go about this in WPF?
A fundamental difference between WPF and GDI/GDI+/WinForms is that WPF uses retained mode rendering (as opposed to the direct rendering of GDI). In a nutshell, this means that the system (actually, the hardware) is taking care of the double buffering for you. Instead of procedurally drawing to the screen / buffer, you rather declaratively provide a tree of vector objects and leave all the rendering to WPF.
The vector objects come in different levels of complexity / abstraction - the most low-level ones you might ever want to deal with are Visuals. The Shapes (Ellipse, Rectangle etc.) mentioned by David are already higher-level objects which can also handle user interaction like hit-testing etc.
You can use any of the WPF shapes, like Ellipse, Rectangle and then using the Canvas class you can move them:
var rect = new Rectangle();
//...set width, height...
Canvas.SetTop(rect, 10);
Canvas.SetLeft(rect, 15);
This should get you started. Keep in mind that zooming, stretching content, traslating and rotations can all be achieved using math functions, but don't panic! WPF's got some cut things about it too:
var rotateTransform1 = new RotateTransform(45);
rect.RenderTransform = rotateTransform1;
If you really, really want it, you can derive your control from UIElement or FrameworkElement and override OnRender where you will get a DrawingContext object which provides methods for drawing shapes, text, images.
But if you want to work in the WPF's philosophy and spirit, probably 99% of the times you don't need to override OnRender. WPF offers a lot (and I really mean A LOT) of ways to develop new controls by styling, templating and if these two don't do the job, then subclassing the appropriate control in the WPF's controls hierarchy.
As gstercken very good pointed before, WPF is not WinForms, you must think in WPF in order to do a good work.

c# control location precision

I need more precision then integer based locations when puttng controls on a form.
It seems control.location only supports Point.
Is there a work around for this?
Point p = new Point(100, 200);
this.Location = p;// this works of course
PointF pF = new PointF(100.04f, 200.08f);
this.Location = pF;// this does not work of course because Location expects a Point not PointF
Is there some setting on the base form, or base control I can set to have more location precision?
You could use Windows Presentation Foundation (WPF) together with XAML (both work nicely within Visual Studio), which allows subpixel positioning of controls.
However, assuming that you are using Windows Forms and not WPF, why would you ever need to put a control on a non-integer (subpixel) location?
Although GDI+ is capable of floating point coordinate systems, Win32 (upon which Winforms is based) is not. I second the reccomendation to move to WPF which has a ubiquitous floating point coordinate system based on device independent virtual pixels.
No, control rendering in WinForms is all fundamentally pixel-based. There is a way you could achieve sub-pixel positioning (without using WPF), but it would be work on your part, and I'm really not sure why you would need this anyway.
The gist of the approach is to create a user control with a hidden instance of the control you're trying place funkily (sub-pixelly, maybe). You wire up all the user control's events so that they pass through to the hidden control, and after each event is passed you call the hidden control's DrawToBitmap method to get a snapshot of the control. You then use Graphics.DrawImage to copy the snapshot to the surface of the user control. DrawImage is not restricted to pixels, so you can offset the drawing by less than a pixel to achieve the precise positioning you're looking for.
Warning: please do not actually do this, as there is no reason for it when you can just use WPF. This would be a lot of work, since "passing the control's events through" is not as simple matter as it sounds. There's also a problem with rendering the focus correctly in this manner, as the invisible control cannot be given the focus (I'm not even going to tell you what the grisly hack solution is to that problem).
Update: It's worth revisiting that decision about WPF - it is ideal for what you're doing and would make your life much simpler. I have been generally underwhelmed by WPF, because I think that while it's very powerful it is essentially overpowered for the uses to which it is most often put (namely, boring-ass business apps). In your case, though, it provides a granularity that you actually require in your app.
If you're stuck in WinForms, however, your best approach is to write your own UserControl versions of the text-editing controls that your application requires. At its core, a TextBox is just a square that you draw a border around and some text on. The .Net Graphics methods for this (DrawRectangle and DrawString) can have the drawing coordinates specified in floating point.
There are tons of StackOverflow questions about owner-drawn user controls and GDI+ graphics.
1 point is 1 pixel and therefore the maximum resolution required.
This is the reason why 0,0 maps to the left corner, and 1024 maps to the right, in a resolution of 1024x768

Simple graphics in C# with default System.Drawing

I would like to develop a simple point&click game in C# with the default drawing libraries...no openGL/SDL/Tao for this project.
Suffice to say, I am curious as to the best ways to draw clickable images in layers on a form.
Ideally, I would have
1) Environment layer (pathways, doors, etc)
2) Object layer (items)
3) Character layer (enemies)
Ideally, the layers beneath other layers would still be viewable, so I could still see the environment underneath an object (so whatever component I use to draw the object to the form needs to be transparent).
This game is going to be tile based...so I will be generating a 2D array of some sort of component and putting those onto the form. The question is, what component should I use? A friend has recommended to generate panels and drop those onto the form and use the background image property, but is there a better way?
I know that this is not the ideal way to develop...this is more of a prototype for myself. Later on I will probably move it to Tao if I get anywhere, but for now (ie, the next year or so), I would like to keep it extremely simple.
Tiles are simply logical chunks with which to organize your UI. You do not need to necessarily have tiles in the form of Panels to use the "tile" idea. Switching tiles can simply mean that your character has reached the right edge of tile A and you will therefore draw tile B and place the character on the left edge of that tile. So your memory structure should be a 2D array of logical tile objects that contain information about what to draw but not necessarily Panels, though that is an option, i don't recommend it.
Layers: You don't really need to worry about layers. All you have to do is draw in the correct sequence: Environment first, followed by objects and then characters. .Net and probably all frameworks paint back to front, which means that things drawn first may be entirely or partially obscured by objects drawn later. The "layering" happens automatically. If you just draw your objects within their own bounds then you do not need to worry about transparency. E.g. a 20x20 pixel character is drawn within a 20x20 pixel bound.
This is all assuming raw e.Graphics.Draw* and e.Graphics.Fill* calls in the Paint event handler of course. As with anything in software, there are 101 ways...

Categories