Draw a stretchable round bracket in WPF - c#

I'm trying to draw a round bracket in WPF. I'm working a Math Editor, so I'll need the bracket to be able to stretch in height as required.
Since most of my stretch text research have failed I've decided to get this accomplished by drawing an arcsegement within my user control, And update it's height each time the UserControl changes in height.
But then there's just one problem, I need each part of my bracket to be in the right thickness (I'm a little bit of a perfectionist). Like a perfect bracket.
Notice some parts of the bracket are thicker than others (especially the middle), Is there a way something like that can be accomplished using arcsegment or do I have to put a normal bracket in a Viewbox, stretch it and experiment till I'm satisfied (rather not though).
Any tips/ideas would be awesome:)

Use 2 ArcSegment to form a PathFigure. Here is a tutorial of combining Arc segments.
<Path Stroke="Black" Fill="Black">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="100,30" IsClosed="True">
<ArcSegment Point="100,130" Size="150 150" />
<ArcSegment Point="100,30" Size="100 100" SweepDirection="Clockwise" />
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>

Related

How does this DrawingBrush Geometry graph grid work?

I just started using Geomectry Drawing in xaml and I came across this interesting article https://msdn.microsoft.com/en-us/library/aa480159.aspx. Here, I find out that the following drawingbrush gives a graph diagram as an output.
<DrawingBrush x:Name="gridBackgroundBrush"
Viewport="0,0,10,10"
ViewportUnits="Absolute"
TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="Green" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="Green" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
From further reading, I figure out that M means starting point or move to, L means line and Z means close but could not figure out how this will give me two lines - one horizontal and one vertical? Any help understanding this will be highly appreciated. Thanks.
So here's a quick break down for you.
Your example is a DrawingBrush which is explicitly set to TileMode="Tile" which is the equivalent of repeat-x/repeat-y if you're more familiar with CSS as example. So it's instructed to repeat itself up-down/left-right repeating.
Your two bits of your Geometry Drawing if translated individually are two squares with one stretching vertical, one stretching horizontal. While your explicitly set ViewportUnits is dictating the size and position effectively making repeated columns and rows.
Your Path Geometry uses Path Markup Syntax to draw these lines as you pointed out. For a more visual explanation replace your Brush on each.
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="Red" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="Blue" />
...and voila! You have yourself a repeated line background with effective vertical/horizontal columns creating your grid. See links for more detail and hope this helps. Cheers!
Oh, and the question you got that from also had a link that would have shed a little light on it but not as much as you'd like so I didn't mark this duplicate.
ADDENDUM:
A little more clarification. Though if you want to learn more I'd follow the documentation link someone spent a lot of time writing to answer this already. Think if you have an x,y grid you're drawing points on.
Say you're using the pen tool in something like Adobe Illustrator, or Blend. Your first click is setting your M as your start point based on the relative size of the container. Then you click in another spot...well now you effectively have a L line.
So when we see: M0,0 L1,0 that's our first starting Line. In this case it's the top corner stretching to the right corner since there's not another anchor in the line between the two points. The next set acts as the anchor to tell that line to change it's direction to make the side, and so on, and so fourth until you hit the end at Z. Hope this helps but I would encourage the documentation first.
Here they are individually if you feel like tinkering with numbers and learning:
<Path Data="M0,0 L1,0 1,0.1, 0,0.1Z"
Height="150" Width="150" Stroke="Red" />
<Path Data="M0,0 L0,1 0.1,1, 0.1,0Z"
Height="150" Width="150" Stroke="Blue" />
I came cross the same thing when I used GMaps V3. It is an SVG path notation path that allows you to draw on WPF and on browsers too. You can find the complete documentation in the link.

Multiple regions for mouseover event in a single image

I have an image in WPF that I would like to have display different information based upon where the mouse is currently hovering. I know I've seen this in websites, I just can't seem to figure out the code to do it in WPF.
The image I'm using is a US map, and I need state specific info to appear as the user crosses the borders. Right now the implementation I'm using is a series of Paths drawn in transparent on top of the map, and then using the Mouse.MouseEnter event to trigger the change. The problem is that the updating seems to suffer from horrible lag, or else the MouseEnter event isn't always catching properly.
Does anybody know of a better way to do this?
Sample C#
private void wyoming_MouseEnter(object sender, MouseEventArgs e)
{
//stateName.Text = "Wyoming";
}
Sample XAML
<Canvas MouseDown="Canvas_MouseDown" Name="canvas">
<Viewbox Stretch="Uniform">
<Image Source="USA.png" />
</Viewbox>
<Path Name="wyoming" Stroke="Transparent" StrokeThickness="1" Mouse.MouseEnter="wyoming_MouseEnter" Mouse.MouseMove="wyoming_MouseMove">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="True" StartPoint="184,121" > <!--NW-->
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="266,129" />
<LineSegment Point="264,193" />
<LineSegment Point="203,190" />
<LineSegment Point="177,186" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
Well, after playing around with this more, I discovered my problem was that I had not filled the paths, only kept them as lines. This basically made for a very small event trigger area, and as such WPF sometimes missed the event. By filling them with Transparent, everything works quickly.
Personally what I did for this same instance (except I was labeling info pertaining to time zones and broadcast areas) was I made transparent path shapes for the areas I want able to be activated on mouseover and laid them over a U.S. Map, then I attached an Event trigger to each for the MouseEnter/MouseLeave events so when the user would mouse over the area of whatever Path, it would fire off that condition and do the action specified....in my instance it was showing radio station broadcast times and programs based on region and time zone. So if an are was Moused over, an info box visibility was set to Visible. On MouseLeave that same info box was set to Collapsed....etc
It was very effective and worked real well and you can make your interactive areas very defined when using the precise shapes you made with your Paths. If I can dig up the source I'll try and share but the project was over a year ago so hopefully the description gives you enough of an idea to get the creativity going. :)

C# Drawing: What is the best way to draw a polygon with a hole in the middle

I have a shape that is defined by an outer border and then an inner border. IF there is no inner boarder, the shape is solid. If there is an inner border I want the polygon/path to be defined only between the two borders; I don't want to draw the outside and then draw the inside in the background color.
For example, if I have a square defined by the following coordinates for the outside border:
{0,0}, {20, 0}, {20,20}, {0, 20}
Then that square which is 20x20 with its bottom left right corner on the origin. That shape then has a triangle cut out of the center:
{10,10}, {15,10}, {15,15}
How can I create a path that contains this shape using either WPF or GDI+?
You can draw that shape with XAML: (The key is to use a CombinedGeometry with GeometryCombineMode="Exclude")
<Path Fill="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,20,20"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<PathGeometry>
<PathFigure StartPoint="10,10">
<LineSegment Point="15,10"/>
<LineSegment Point="15,15"/>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
In GDI+, you can use FillPath() or DrawPath() with FillModeAlternate.
There's an example pretty close to what you're asking for here.
Just draw the holes on top of the main contour using the background color. It will look as if they were real holes
edit
use this approach if the api you are using does not support holes. Which is why I assume you are asking

C# WPF grab screenshot with SnippingTool effect

I'm trying to integrate a screenshot grabbing feature in my WPF app and I'd like it to look like snipping tool.
So far I've managed accomplish something similar by creating a fullscreen window (with a canvas) with opacity set to 0.5 and dark background. When I click somewhere and start dragging, a white rectangle is drawn, generating an effect similar to this.
What I'd like to have is the inner part of that rectangle opening a opacity hole in the background canvas, so that I could see through the selected area - just like snipping tool.
Problem is, being fairly new to .NET, I have no idea how or where to start. Did some research and tests on the OpacityMask field of the screenshot window but got nowhere.
Here's a little vid to show the current effect.
Edit: Also, as bonus question, is there an easy way to grab a screenshot that spans across multiple monitors (virtual screen)? Graphics.CopyFromScreen() only seems to work for 1 screen.
Already fixed this and seems to work for all possible weird virtual desktop layouts:
// Capture screenie (rectangle is the area previously selected
double left = Canvas.GetLeft(this.rectangle);
double top = Canvas.GetTop(this.rectangle);
// Calculate left/top offset regarding to primary screen (where the app runs)
var virtualDisplay = System.Windows.Forms.SystemInformation.VirtualScreen;
var primaryScreen = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
if (virtualDisplay.Left < primaryScreen.Left)
{
left -= Math.Abs(virtualDisplay.Left - primaryScreen.Left);
}
if (virtualDisplay.Top < primaryScreen.Top)
{
top -= Math.Abs(virtualDisplay.Top - primaryScreen.Top);
}
You can have a CombinedGeometry with GeometryCombineMode="Exclude" creating a "punched" effect. Sample:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" AllowsTransparency="True"
WindowStyle="None" Background="Transparent">
<Canvas >
<Path Stroke="Black" Fill="White" Opacity=".5">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,800,600" >
</RectangleGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<RectangleGeometry Rect="50,50,100,100" >
</RectangleGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Canvas>
</Window>

Combining two semi-transparent ellipses

Have a strange one. I have two ellipses that have an opacity of 0.7. What I'd like to do, is where the two ellipses cross, show a different color. In an old WF image I'd have run through each pixel and swapped colours, but I'm not sure how to do this with a layer in Silverlight. Anyone have any ideas?
Thanks!
edit: Sorry, there were a few errors with the properties of the various elements. This is tested:
Create a Path and put as Path.Data a GeometryGroup that has the two EllipseGeometries as child elements. Set GeometryGroup.FillRule to "EvenOdd" so that the area that both ellipses cover is not filled, and set "Fill" to the color you want the ellipses to have (here: AliceBlue).
Put that Path into a Control with "Background" property, like Border, and set that Background to the color you want the area both ellipses are covering to be (here: yellow).
Then you set Clip to the same GeometryGroup with FillRule set to "Nonzero" to prevent the area around the ellipses to also be painted with the background color.
<Border Background="Yellow">
<Path Fill="AliceBlue" Stroke="Black" StrokeThickness="4">
<Path.Data>
<GeometryGroup FillRule="EvenOdd">
<EllipseGeometry Center="100,100" RadiusX="40" RadiusY="80" />
<EllipseGeometry Center="100,100" RadiusX="80" RadiusY="40" />
</GeometryGroup>
</Path.Data>
</Path>
<Border.Clip>
<GeometryGroup FillRule="Nonzero">
<EllipseGeometry Center="100,100" RadiusX="40" RadiusY="80" />
<EllipseGeometry Center="100,100" RadiusX="80" RadiusY="40" />
</GeometryGroup>
</Border.Clip>
</Border>
If you need both ellipses to be painted in different colors use two Border and Path objects, use the same GeometryGroup with "EvenOdd" and set each of Border.Clip to one EllipseGeometry object.
If you need a more detailed definition use a PathGeometry instead of GeometryGroup and define the area with ArcSegments.

Categories