I'm creating a speech bubble control for my application, and the way I'm looking to do it is to use a rectangle with rounded corners, then place a shape on top that forms the "origin" of the speech bubble. These are arranged in a Grid so that the bubble resizes to its content whilst keeping the origin shape constant (i.e. it won't stretch). Now, here's my question; is it possible to create a Path in WPF with one of the sides omitted (i.e. so the stroke is omitted from that edge, but the fill is still present)?
I know I could do it by placing 2 shapes on top of each other, but I'm looking for a solution that's as simple as possible!
Thanks, Lee.
Yes, it's possible. You just omit one of the edges. The Fill will still be applied inside the shape:
<Path Fill="Beige" Stroke="Black" Data="M 0,0 L 20,0 L 0,20"></Path>
Related
I have a WPF Touch app (MS Surface, VS 2017, .NET 4.7) that shows a number of simple shapes (lines, rects, circles) above an image, all on on a canvas. I'm having a trouble with selecting my ManipulationContainer for touch.
Roughly what I have is this:
<ScrollViewer x:Name="MyViewer"
ManipulationStarting="Viewer_ManipulationStarting">
<Canvas x:Name="MyCanvas">
<Image x:Name="MyImage" Source={Binding MyImageSource}"/>
<ItemsControl x:Name="MyShapes" ItemsSource="{Binding MyShapes}"/>
</Canvas>
</ScrollViewer>
I want let my user do two different things with touch.
With one finger they can draw new shapes (relative to the canvas)
With two fingers they can zoom the entire canvas (relative to the scrollviewer)
So if the user is drawing a new shape, then ManipulationContainer must be "MyCanvas". But if the user is zooming the whole scene, then the ManipulationContainer must be "MyViewer" (because in that case I'm changing the LayoutTransform of the whole canvas).
So I need (it would seem) to select from one of two different manipulation containers depending on which of these operations is happening. But I can't seem to figure out how. Below is what I have (which doesn't work) where I choose the container. in the ManipulationStarting handler.
private void Scene_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
// If zooming, container is the parent viewer. Otherwise it's
// drawing a shape relative to the canvas.
if (e.Manipulators.Count() >= 2)
e.ManipulationContainer = MyViewer; // Zooming whole canvas
else
e.ManipulationContainer = MyCanvas; // Drawing on canvas
e.Handled = true;
}
As you likely guessed, when I first get this, I always get just one manipulator; The user is extremely unlikely to have his very first touch be with two fingers exactly simultaneously. So my code always thinks I'm drawing a shape.
It's only later on, in the ManipulationDelta that I start getting more than one manipulator. But it's too late then to choose a container. It's already been chosen. And if I check the number of manipulators then, my coordinates, delta, and origin are all relative to the very thing I'm trying to move. It makes the zooming jump all over the place.
I don't know what to do about this. I have to let my user zoom at any time so I do not have the option of forcing them to choose a "zoom tool".
I'm sure I'm missing something simple but I don't know what it is and I'd like to avoid blind alleys. Any suggestions?
I'm currently doing a CFD simple problem with C# in WPF analyzing a quasi-one-dimensional flow (only varying with x) and I want to represent the results in a "decent" way. Hence, imagine it as a rectangle with a given number of vertical sections. The form is not a rectangle, but a nozzle. What I was wondering is if there is a way of representing with Stackpanels or something similar a certain form.
In the image attached the shape can be seen, to help understand the problem.
Every section (a rectangle "cut" by the edges of the nozzle) has a temperature associated and already computed.Just to give an example, a temperature value of 250 for the section drawn, and for example I want to paint it with a Red color.
My question is: Is there any way of "shaping" stackpanels or something similar to display something like the shape shown?
I've searched for information and this is the most similar option found:
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="200,200" Point2="300,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
Which draws this image. What I would like to construct is the nozzle with this method and be able to divide it or place vertical segments inside it as suggested at the first image, painting them according to the value they have.
You have defined a pretty complex problem which may be too much for a single SO question. By no means am I providing a complete solution to your problem. But maybe it will be enough to point you in the right direction. From there, you can start on your own solution and ask further questions if you get stuck.
Your best solution is probably to manually draw shapes on the canvas using c# (or possibly XAML).
Here's the best link I could find after a quick search.
https://msdn.microsoft.com/en-us/library/ms751808(v=vs.100).aspx
It is a Microsoft tutorial of drawing Geometry and Geometric Shapes in XAML and code.
See the section about path geometries.
I would think that by combining two ArcSegments for the curved sides and LineSegments connecting the two sides that you could get the basic shape you are looking for.
I think that for your rectangular "cuts", you will have to build those explicitly in code as well. It will be tricky to match their shape exactly when overlaying them over the nozzle. One simple work around could be to create all your horizontal bars and paint them. Then create a top and a bottom white overlay that covers up the rectangles. One overlay would have the shape of the top nozzle and cover the parts of the rectangles you don't want shown. And similarly for another shape that makes up the bottom of the nozzle.
i've been looking for some way to create a shape, and i found Here this article about it,but i'm not sure how to use this, there's no tutorial to explain how to use each numbers inside of Data!
<Path Stroke="DarkGoldenRod" StrokeThickness="3"
Data="M 100,200 C 100,25 400,350 400,175 H 280"/>
I know this, "M" its the starter point, but its just beyond me!
Use blend to draw you shape. open your project in blend and draw whatever shape you want here the the tutorial
Draw shapes and paths in Blend
Hope it helps
I have to draw some custom shapes in wpf, like Square, Ellipse, Spade etc etc as shown in the image.
Now I need to apply some simple borders to those shapes like shown in the image,
How should I achieve it. Shape size id variable, it could be small, medium, large and extra large.
what I have done till now is draw all the images using this
Ellipse
<Ellipse Width='4' Height='4' Stroke='Green' Fill='Red'>
Triangle
<Polygon Points='2 0, 4 4,0 4' Stroke='Green' Fill='Red'>
Spade
<Polygon Points='2 0, 4 2,2 4,0 2' Stroke='Green' Fill='Red'> and so on.
The first border with simple line is not a problem. I could use a simple border or just change the size of stroke so they show they have a border, problem lies in dashed lines and double lines border
Check a set of Stroke... properties of Shape class
StrokeThickness - to set thickness,
StrokeDashArray - to setup dashed pattern
Regarding last two items in second drop down - I do not see an easy way of implementing such border for any generic shape.
[Update] Check this question it contains some ideas applicable to your situation
I have had the problem described in the question Tiling rectangles seamlessly in WPF, but am not really happy with the answers given there.
I am painting a bar chart by painting lots of rectangles right next to each other. Depending on the scale of the canvas containing them, there are small gaps visible between some of them as a result from sub-pixel rendering.
I learned from the above question how to make my rectangles fit with the screen pixels, removing that effect.
Unfortunately, my chart may display way more bars than there are pixels. Apart from the tiny gaps (which manifest as a periodic change in color saturation), this works well. If I snap each bar with the screen pixels, most of the bars vanish, though, so I am looking for another solution.
Thanks in advance!
Cause of the problem
Subpixel shapes use alpha blending within the pixel. Unfortunately there is no alpha blending algorithm that results in the rectangles blending seamlessly when abutted.
For example, if:
The background color is white
The foreground color is black, and
You have two rectangles, each covering half of a single pixel
Each rectangle will be painted as black with 50% opacity. The first converts the white pixel to gray. The second converts it to a darker gray, but not black. If these rectangles continue black in adjacent pixels you see a dark gray pixel among the black.
Two types of solutions
There are two general ways to solve this problem:
Use a single Geometry to define all your rectangles, or
Force the initial rendering to be at a high enough resolution your user won't see the problem.
How to use a single Geometry
If you just have a set of Rectangles, you can create a simple control that paints over the whole set of rectangles with a single PathGeometry containing the combined shape. To illustrate the idea, if you had two rectangles beside each other of different heights, like this:
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="1.5" Height="2" Fill="Red" />
<Rectangle Canvas.Left="1.5" Canvas.Top="0" Width="1.5" Height="4" Fill="Red" />
You could render it with a single PathGeometry like this:
<Path Data="M0,0 L0,2 L1.5,2 L1.5,4 L3,4 L3,0 Z" Fill="Red" />
A practical way to implement this is to:
Paint your rectangles with a Transparent brush so they will be clickable but not visable
Add a Path control underneath the rectangles in Z order
Data binding the Data property of your Path control to your data source with a converter that constructs the geometry.
If you are using the layout system to position your rectangles, you may instead want to use an AdornerLayer by creating an Adorner for each rectangles, then when rendering the adorners compute the combined path for the first one and make the rest invisible.
The above assumes it is easy to generate the PathGeometry from the source data. For more complex scenarios, the Path control can be subclassed to search the visual tree of its parent for specified shapes and use general geometricl algorithms to compute a PathGeometry that represents the union of them with no extra edges.
If your rectangles will have multiple colors, you can use multiple Path controls one per color, or you can construct a Drawing object and show that.
Here is the structure of the code to construct a PathGeometry:
var geo = new PathGeometry();
var figure = new PathFigure();
var segment = new PolyLineSegment();
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
figure.Segments.Add(segment);
geo.Figures.Add(figure);
How to force the initial rendering to be at high resolution
To force rendering at higher resolution:
Internally construct your chart several times larger than you want to display it, for example by wrapping it in a ViewBox.
Use a VisualBrush or RenderTargetBitmap to force your chart to be rendered separately
Add a Rectangle painted with that VisualBrush to your UI
Note that normally WPF is clever about rendering at the actual resolution required when you use a ViewBrush, but it can be tricked by having the actual chart actually display on the screen at the larger size, but then be clipped by a parent control so you don't actually see the too-big version.
This problem doesn't exist with RenderTargetBitmap, of course, since you specify the resolution you want, but it can be tricky knowing when to re-render the bitmap. If you only re-render on data changes you can use an event, but if you want any visual change to trigger a re-render it is more difficult.