Wavy underlines in a FlowDocument - wpf

In WPF, is there an easy way to add wavy underlines (like spelling errors in Word) to FlowDocument elements? There's the Underline class, but there seems to be no way to style it.

You can create the wavy effect using the following changes to Robert Macne's solution
Add a visual brush to the Grid.Resources section:
<VisualBrush x:Key="WavyBrush" Viewbox="0,0,3,2" ViewboxUnits="Absolute" Viewport="0,0.8,6,4" ViewportUnits="Absolute" TileMode="Tile">
<VisualBrush.Visual>
<Path Data="M 0,1 C 1,0 2,2 3,1" Stroke="Red" StrokeThickness="0.2" StrokeEndLineCap="Square" StrokeStartLineCap="Square" />
</VisualBrush.Visual>
</VisualBrush>
And change the pen to:
<Pen Brush="{StaticResource WavyBrush}" Thickness="6" />

A red underline is simple enough:
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<FlowDocument x:Key="doc">
<Paragraph>
<Run Text="This text is underlined in red.">
<Run.TextDecorations>
<TextDecoration Location="Underline">
<TextDecoration.Pen>
<Pen Brush="Red" Thickness="1" DashStyle="{x:Static DashStyles.Dot}"/>
</TextDecoration.Pen>
</TextDecoration>
</Run.TextDecorations>
</Run>
</Paragraph>
</FlowDocument>
</Grid.Resources>
<FlowDocumentReader Document="{StaticResource doc}"/>
</Grid>
A wavy red underline would be a bit more involved, but I think you could create a VisualBrush with a wavy red thing in it, and set that as the Brush of the Pen that you specify for the underlining TextDecoration. Edit: see bstoney's post for this.

Here is #bstoney's solution implemented in code.
Pen path_pen = new Pen(new SolidColorBrush(Colors.Red), 0.2);
path_pen.EndLineCap = PenLineCap.Square;
path_pen.StartLineCap = PenLineCap.Square;
Point path_start = new Point(0, 1);
BezierSegment path_segment = new BezierSegment(new Point(1, 0), new Point(2, 2), new Point(3, 1), true);
PathFigure path_figure = new PathFigure(path_start, new PathSegment[] { path_segment }, false);
PathGeometry path_geometry = new PathGeometry(new PathFigure[] { path_figure });
DrawingBrush squiggly_brush = new DrawingBrush();
squiggly_brush.Viewport = new Rect(0, 0, 6, 4);
squiggly_brush.ViewportUnits = BrushMappingMode.Absolute;
squiggly_brush.TileMode = TileMode.Tile;
squiggly_brush.Drawing = new GeometryDrawing(null, path_pen, path_geometry);
TextDecoration squiggly = new TextDecoration();
squiggly.Pen = new Pen(squiggly_brush, 6);
text_box.TextDecorations.Add(squiggly);

I know this is an old question but I prefer this brush. It's a little angular but very clean.
<VisualBrush x:Key="WavyBrush">
<VisualBrush.Visual>
<Path Data="M 0,2 L 2,0 4,2 6,0 8,2 10,0 12,2" Stroke="Red"/>
</VisualBrush.Visual>
</VisualBrush>

Another way can be : Creating a drawing group with two lines(kind of inverted V) and passing that drawing group as content for drawing brush and having Tile as mode so that it can repeat. But here peaks will be pointed as we are drawing two lines, one starts from others end.
Sample will look like :
// Configuring brush.
DrawingGroup dg = new DrawingGroup();
using (DrawingContext dc = dg.Open())
{
Pen pen = new Pen(Brushes.Red, 1);
dc.DrawLine(pen, new System.Windows.Point(0.0, 0.0), new System.Windows.Point(3.0, 3.0));
dc.DrawLine(pen, new System.Windows.Point(3.0, 3.0), new System.Windows.Point(5.0, 0.0));
}
public DrawingBrush brush = new DrawingBrush(dg);
brush.TileMode = TileMode.Tile;
brush.Viewport = new Rect(0, 0, 4, 4);
brush.ViewportUnits = BrushMappingMode.Absolute;
// Drawing line on VisualCollection
private VisualCollection visualCollection = new VisualCollection(this);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext drawingContext = dv.RenderOpen())
{
drawingContext.DrawLine(new Pen(brush, 2), new Point(50, 100), new Point(200, 100));
base.OnRender(drawingContext);
}
this.visualCollection.Add(dv);

Related

Which container should I use in WPF to draw geometric shapes with correct positioning?

I want to use Shapes in WPF to display some mathematically defined objects (dots, polylines, reference axes) in a way that is similar to a geometric chart or plot. I want to use Shapes because of their interactivity, since the user is supposed to click over them, highlight them with mouseover, etc.
The Shape objects themselves are to be databound to their geometric definitions in the ViewModel. I can choose the type of each property according to what would me most convenient (PointCollection, PathFigure, Point, etc.).
Problem is: so far, I am trying with Canvas container, which has some particular layout characteristics which make it hard for me to get it right. Specifically, it has its origin on top-left, so my shapes appear upside down unless I use RenderTransform (which I do not oppose to do);
Besides that, I have a BoundingBox property in ViewModel (of type Rect) which should be used to "fit" or "autozoom" inside the control, but since model coordinates are not screen coordinates, I would have to apply some Transform.
Unfortunately, I can only apply Transforms to Geometries, and I can do so using an Image with DrawingImage as source, with GeometryDrawings describing the shapes. But then I lose all the required characteristics of Shapes in the first place (styling and interaction mostly).
And that's why I am stuck, so my question boils down to:
"How can I transform the geometry of shapes so that they are correctly positioned inside of a 'reference viewport' in a Canvas?"
Here is some unsatisfactory code, with the Image control displaying the desired layout:
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DrawingGraficos"
x:Class="DrawingGraficos.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="204.333" Height="181">
<Window.DataContext>
<local:DesenhoViewModel/>
</Window.DataContext>
<Window.Resources>
<local:TranslacaoConverter x:Key="TranslacaoConverter"/>
</Window.Resources>
<UniformGrid Rows="0" Columns="2">
<Canvas x:Name="canvasviewport">
<Polygon Points="{Binding BoundingBoxCorners}" Fill="LightGray"/>
<Path Stroke="Red" StrokeThickness="2" Data="{Binding GeometriaLinhaSimetria}"/>
</Canvas>
<Image>
<Image.LayoutTransform>
<ScaleTransform ScaleY="-1" CenterY=".5"/>
</Image.LayoutTransform>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.ClipGeometry>
<RectangleGeometry Rect="{Binding Limites}"/>
</DrawingGroup.ClipGeometry>
<GeometryDrawing Brush="LightGray">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="{Binding Limites}"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry="{Binding GeometriaLinhaSimetria}">
<GeometryDrawing.Pen>
<Pen Brush="Red" Thickness="2"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</UniformGrid>
</Window>
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Miotec.MVVM;
using System.Windows;
using System.Windows.Media;
namespace DrawingGraficos
{
public class DesenhoViewModel : ViewModelBase {
public Rect Limites {
get {
double largura = 70;
double altura = 100;
return new Rect(new Point(-largura*0.5,-30), new Point(largura*0.5,altura-30));
}
}
public PointCollection BoundingBoxCorners {
get {
return new PointCollection() {
Limites.BottomLeft, Limites.TopLeft, Limites.TopRight, Limites.BottomRight
};
}
}
public Point Origem { get { return new Point(0,0); } }
public List<Point> LinhaSimetria {
get {
return new List<Point> {
new Point(-3,-20),
new Point(0,-15),
new Point(2,-10),
new Point(4,-5),
new Point(4,0),
new Point(2,5),
new Point(2,10),
new Point(0,15),
new Point(-2,20),
new Point(-2,25),
new Point(-2,30),
new Point(-2,35)
};
}
}
public Geometry GeometriaLinhaSimetria {
get {
var sb = new StringBuilder("M");
foreach (var p in LinhaSimetria) {
sb.AppendFormat(" {0};{1}", p.X, p.Y);
}
string result = sb.ToString().Replace(",",".").Replace(";",",");
return Geometry.Parse(result);
}
}
}
}

WPF Rub out top image to reveal image underneath

As the title suggests, using WPF I want to have a scenario where I have a bitmap image with another bitmap overlayed on top of it and, using the mouse, "paint" over the top bitmap so that it reveals the bitmap underneath. Is this just as simple as painting with a transparent brush? I have tried this to no avail but maybe I am missing something.
You can use a VisualBrush to create an OpacityMask. Here is a code example of a dark green rectangle being replaced by a light green one. Using this approach the two rectangles could be any elements including images.
<Grid MouseMove="Grid_MouseMove">
<Rectangle Fill="DarkGreen"/>
<Rectangle Fill="LightGreen">
<Rectangle.OpacityMask>
<VisualBrush Stretch="None" AlignmentX="Left" AlignmentY="Top">
<VisualBrush.Visual>
<Path Name="path" Stroke="Black" StrokeThickness="10"/>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
and here is the code-behind:
private void Grid_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var point = e.GetPosition(sender as Grid);
if (lastPoint != nullPoint)
AddSegment(lastPoint, point);
lastPoint = point;
}
else
{
lastPoint = nullPoint;
}
}
private void AddSegment(Point point1, Point point2)
{
if (segments.Count == 0 || segments[segments.Count - 1].Point != point1)
segments.Add(new LineSegment(point1, false));
segments.Add(new LineSegment(point2, true));
var figures = new PathFigureCollection();
figures.Add(new PathFigure(new Point(), segments, false));
var geometry = new PathGeometry();
geometry.Figures = figures;
path.Data = geometry;
}
List<LineSegment> segments = new List<LineSegment>();
private static readonly Point nullPoint = new Point(-1, -1);
Point lastPoint = nullPoint;

WPF. Easiest way to move Image to (X,Y) programmatically?

Does anyone know of an easy way to animate a movement from an Image's current location to a new location (X,Y) using WPF animation with no XAML, 100% programmatically? And with no reference to "this" (with RegisterName etc).
I am trying to make an extension class for Image to do animation stuff on it. It is easy enough to change the width and height properties through animation, but after searching for location animation of an object it suddenly becomes more advanced.
As it is an extension class I will only have a reference to the actual Image object and the X and Y I want to move it to.
public static void MoveTo(this Image targetControl, double X, double Y, double Width, double Height){
//code here
...
}
Update:
Thanks. Almost working. It seems The GetTop and GetLeft returns 'NaN' not explicitly set. Found the workaround in this post: Canvas.GetTop() returning NaN
public static void MoveTo(this Image target, double newX, double newY) {
Vector offset = VisualTreeHelper.GetOffset(target);
var top = offset.Y;
var left = offset.X;
TranslateTransform trans = new TranslateTransform();
target.RenderTransform = trans;
DoubleAnimation anim1 = new DoubleAnimation(0, newY - top, TimeSpan.FromSeconds(10));
DoubleAnimation anim2 = new DoubleAnimation(0, newX - left, TimeSpan.FromSeconds(10));
trans.BeginAnimation(TranslateTransform.YProperty, anim1);
trans.BeginAnimation(TranslateTransform.XProperty, anim2);
}
I had to swap two of the values (FROM) with 0. I assume that must be because in this context the upper left corner of the picture is the origin? But now it works.
Try this:
public static void MoveTo(this Image target, double newX, double newY)
{
var top = Canvas.GetTop(target);
var left = Canvas.GetLeft(target);
TranslateTransform trans = new TranslateTransform();
target.RenderTransform = trans;
DoubleAnimation anim1 = new DoubleAnimation(top, newY - top, TimeSpan.FromSeconds(10));
DoubleAnimation anim2 = new DoubleAnimation(left, newX - left, TimeSpan.FromSeconds(10));
trans.BeginAnimation(TranslateTransform.XProperty,anim1);
trans.BeginAnimation(TranslateTransform.YProperty,anim2);
}
Here it is... It changes the size and moves a MediaElement under the Canvas. Just input your parameters:
Storyboard story = new Storyboard();
DoubleAnimation dbWidth = new DoubleAnimation();
dbWidth.From = mediaElement1.Width;
dbWidth.To = 600;
dbWidth.Duration = new Duration(TimeSpan.FromSeconds(.25));
DoubleAnimation dbHeight = new DoubleAnimation();
dbHeight.From = mediaElement1.Height;
dbHeight.To = 400;
dbHeight.Duration = dbWidth.Duration;
story.Children.Add(dbWidth);
Storyboard.SetTargetName(dbWidth, mediaElement1.Name);
Storyboard.SetTargetProperty(dbWidth, new PropertyPath(MediaElement.WidthProperty));
story.Children.Add(dbHeight);
Storyboard.SetTargetName(dbHeight, mediaElement1.Name);
Storyboard.SetTargetProperty(dbHeight, new PropertyPath(MediaElement.HeightProperty));
DoubleAnimation dbCanvasX = new DoubleAnimation();
dbCanvasX.From = 0;
dbCanvasX.To = 5;
dbCanvasX.Duration = new Duration(TimeSpan.FromSeconds(.25));
DoubleAnimation dbCanvasY = new DoubleAnimation();
dbCanvasY.From = 0;
dbCanvasY.To = 5;
dbCanvasY.Duration = dbCanvasX.Duration;
story.Children.Add(dbCanvasX);
Storyboard.SetTargetName(dbCanvasX, mediaElement1.Name);
Storyboard.SetTargetProperty(dbCanvasX, new PropertyPath(Canvas.LeftProperty));
story.Children.Add(dbCanvasY);
Storyboard.SetTargetName(dbCanvasY, mediaElement1.Name);
Storyboard.SetTargetProperty(dbCanvasY, new PropertyPath(Canvas.TopProperty));
story.Begin(this);
<Viewbox Stretch="Uniform" StretchDirection="Both" SnapsToDevicePixels="True">
<Grid Width="640" Height="480" Name="MainLayout" SnapsToDevicePixels="True" Background="Black">
<Canvas Width="640" Height="480" Name="MainCanvas" SnapsToDevicePixels="True">
<MediaElement Height="171" HorizontalAlignment="Left" Name="mediaElement1" VerticalAlignment="Top" Width="337" LoadedBehavior="Manual" Margin="166,140,0,0" Canvas.Left="-162" Canvas.Top="-140" />
<Button Canvas.Left="294" Canvas.Top="196" Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
</Canvas>
</Grid>
</Viewbox>
UPDATE:
Instead of MediaElement use this line:
<Rectangle Height="171" HorizontalAlignment="Left" Name="mediaElement1" VerticalAlignment="Top" Width="337" Margin="166,140,0,0" Canvas.Left="-162" Canvas.Top="-140" Fill="{DynamicResource {x:Static SystemColors.MenuBarBrushKey}}" />
And don't forget to put the C# code to:
private void button1_Click(object sender, RoutedEventArgs e) {}
You can use MediaElement as well but you have to define a VideoClip to see something ;)
Please find a solution that uses the Left and Top properties of Canvas for the extension method. See the following code:
public static void MoveTo(this Image target, Point newP)
{
Point oldP = new Point();
oldP.X = Canvas.GetLeft(target);
oldP.Y = Canvas.GetTop(target);
DoubleAnimation anim1 = new DoubleAnimation(oldP.X, newP.X, TimeSpan.FromSeconds(0.2));
DoubleAnimation anim2 = new DoubleAnimation(oldP.Y, newP.Y , TimeSpan.FromSeconds(0.2));
target.BeginAnimation(Canvas.LeftProperty , anim1);
target.BeginAnimation(Canvas.TopProperty, anim2);
}
This code is based on #DeanChalk's answer.
It moves an Image contained within a Canvas (RFID_Token) diagonally from the top-right to the bottom-left, positioned centrally over another Image within a Canvas (RFID_Reader).
<Canvas>
<Canvas x:Name="RFID_Reader_Canvas">
<Image x:Name="RFID_Reader" Source="RFID-Reader.png" Height="456" Width="682" Canvas.Left="37" Canvas.Top="524"/>
</Canvas>
<Canvas x:Name="RFID_Token_Canvas">
<Image x:Name="RFID_Token" Source="RFID-Token.png" Height="268" Width="343" Canvas.Left="874" Canvas.Top="70"/>
</Canvas>
</Canvas>
var StartX = Canvas.GetLeft(RFID_Token);
var StartY = Canvas.GetTop(RFID_Token);
var EndX = RFID_Reader.Width / 2 + Canvas.GetLeft(RFID_Reader) - StartX - (RFID_Token.Width / 2);
var EndY = RFID_Reader.Height / 2 + Canvas.GetTop(RFID_Reader) - StartY - (RFID_Token.Height / 2);
var AnimationX = new DoubleAnimation(0, EndX, TimeSpan.FromSeconds(1));
var AnimationY = new DoubleAnimation(0, EndY, TimeSpan.FromSeconds(1));
var Transform = new TranslateTransform();
RFID_Token_Canvas.RenderTransform = Transform;
Transform.BeginAnimation(TranslateTransform.XProperty, AnimationX);
Transform.BeginAnimation(TranslateTransform.YProperty, AnimationY);
I kept having NaN or 0 values for my nested elements, here's a modified version of Danny's answer :
public void MoveTo(Canvas canvas, FrameworkElement target, FrameworkElement destination)
{
Point oldPoint = target.TransformToAncestor(canvas).Transform(new Point(0, 0));
Point newPoint = destination.TransformToAncestor(canvas).Transform(new Point(0, 0));
var EndX = destination.Width / 2 + newPoint.X - oldPoint.X - (target.Width / 2);
var EndY = destination.Height / 2 + newPoint.Y - oldPoint.Y - (target.Height / 2);
TranslateTransform trans = new TranslateTransform();
target.RenderTransform = trans;
DoubleAnimation anim1 = new DoubleAnimation(0, EndX, TimeSpan.FromSeconds(0.3));
DoubleAnimation anim2 = new DoubleAnimation(0, EndY, TimeSpan.FromSeconds(0.3));
trans.BeginAnimation(TranslateTransform.XProperty, anim1);
trans.BeginAnimation(TranslateTransform.YProperty, anim2);
}

saving WPF InkCanvas to a JPG - image is getting cropped

I have a WPF InkCanvas control I'm using to capture a signature in my application. The control looks like this - it's 700x300
However, when I save it as a JPG, the resulting image looks like this, also 700x300
The code I'm using to save
sigPath = System.IO.Path.GetTempFileName();
MemoryStream ms = new MemoryStream();
FileStream fs = new FileStream(sigPath, FileMode.Create);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)inkSig.Width, (int)inkSig.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(inkSig);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(fs);
fs.Close();
This is the XAML I'm using:
<Window x:Class="Consent.Client.SigPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent" Topmost="True" AllowsTransparency="True"
Title="SigPanel" Left="0" Top="0" Height="1024" Width="768" WindowStyle ="None" ShowInTaskbar="False" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" >
<Border BorderThickness="1" BorderBrush="Black" Background='#FFFFFFFF' x:Name='DocumentRoot' Width='750' Height='400' CornerRadius='10'>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Name="txtLabel" FontSize="24" HorizontalAlignment="Center" >Label</TextBlock>
<InkCanvas Opacity="1" Background="Beige" Name="inkSig" Width="700" Height="300" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Button FontSize="24" Margin="10" Width="150" Name="btnSave" Click="btnSave_Click">Save</Button>
<Button FontSize="24" Margin="10" Width="150" Name="btnCancel" Click="btnCancel_Click">Cancel</Button>
<Button FontSize="24" Margin="10" Width="150" Name="btnClear" Click="btnClear_Click">Clear</Button>
</StackPanel>
</StackPanel>
</Border>
In the past this worked perfectly. I can't figure out what changed that is causing the image to shift when it is saved.
I had same problem i did this way.. It worked here..
private void Button_Click(object sender, RoutedEventArgs e)
{
double width = inkSig.ActualWidth;
double height = inkSig.ActualHeight;
RenderTargetBitmap bmpCopied = new RenderTargetBitmap((int)Math.Round(width), (int)Math.Round(height), 96, 96, PixelFormats.Default);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(inkSig);
dc.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), new System.Windows.Size(width, height)));
}
bmpCopied.Render(dv);
System.Drawing.Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
// from System.Media.BitmapImage to System.Drawing.Bitmap
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bmpCopied));
enc.Save(outStream);
bitmap = new System.Drawing.Bitmap(outStream);
}
EncoderParameter qualityParam =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 85L);
// Jpeg image codec
ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg");
if (jpegCodec == null)
return;
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
Bitmap btm = new Bitmap(bitmap);
bitmap.Dispose();
btm.Save("C:\\Users\\Pd\\Desktop\\dfe12.jpg", jpegCodec, encoderParams);
btm.Dispose();
}
private ImageCodecInfo getEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
Aha! The problem is the TextBlock txtLabel that is directly above the InkCanvas. When you remove that the black line disappears.
As for why that is happening, I'm not entirely sure yet.
My class save image
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
public void ExportToJpeg(String path, InkCanvas surface)
{
double
x1 = surface.Margin.Left,
x2 = surface.Margin.Top,
x3 = surface.Margin.Right,
x4 = surface.Margin.Bottom;
if (path == null) return;
surface.Margin = new Thickness(0, 0, 0, 0);
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96,
96,
PixelFormats.Default);
renderBitmap.Render(surface);
using (FileStream fs = File.Open(path, FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(fs);
}
surface.Margin = new Thickness(x1, x2, x3, x4);
}
and
surface.Margin = new Thickness(55,40,96,5);
http://img519.imageshack.us/img519/7499/mynewimage.png
Jason, I solved this problem.
Sorry my English. I am Russian.
You need set property inkCanvas.Margin at 0,0,0,0
with:
surface.Margin = new Thickness(0, 0, 0, 0);
after saving set margin at your position.
example:
http://img189.imageshack.us/img189/7499/mynewimage.png
var size = new Size(inkCanvas.ActualWidth, inkCanvas.ActualHeight);
inkCanvas.Margin = new Thickness(0, 0, 0, 0);
inkCanvas.Measure(size);
inkCanvas.Arrange(new Rect(size));
var encoder = new PngBitmapEncoder();
var bitmapTarget = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Default);
bitmapTarget.Render(inkCanvas);
encoder.Frames.Add(BitmapFrame.Create(bitmapTarget));
encoder.Save(ms);
I've been looking all over the net for an answer to this problem and tried most opinions without any joy. Then I tried this and it worked!
<Canvas x:Name="editCanvas" Background="Transparent" ClipToBounds="True">
<InkCanvas EditingMode="Select" x:Name="inkCanvas" Background="Transparent" Height="562" Width="866">
</InkCanvas>
</Canvas>

WPF rectangle - round just top corners

How can I have just the top corners rounded for a WPF rectangle?
I created a border and set the CornerRadius property and inside the border I've added my rectangle, but it doesn't work, the rectangle is not rounded.
<Border BorderThickness="1" CornerRadius="50,50,0,0" BorderBrush="Black">
<Rectangle Fill="#FF5A9AE0" Stretch="UniformToFill" ClipToBounds="True"/>
</Border>
The problem you've got is that the rectangle is "overflowing" the rounded corners of your border.
A rectangle can't have individually rounded corners, so if you just put the background colour on the border and remove the rectangle:
<Border BorderThickness="1" Grid.Row="0" Grid.ColumnSpan="2"
CornerRadius="50,50,0,0" BorderBrush="Black" Background="#FF5A9AE0">
</Border>
You'll get your desired effect.
Set the RadiusX and RadiusY properties on the rectangle, this will give it rounded corners
Good example how its possible to do OnRender with DrawingContext:
/// <summary>
/// Draws a rounded rectangle with four individual corner radius
/// </summary>
public static void DrawRoundedRectangle(this DrawingContext dc, Brush brush,
Pen pen, Rect rect, CornerRadius cornerRadius)
{
var geometry = new StreamGeometry();
using (var context = geometry.Open())
{
bool isStroked = pen != null;
const bool isSmoothJoin = true;
context.BeginFigure(rect.TopLeft + new Vector(0, cornerRadius.TopLeft), brush != null, true);
context.ArcTo(new Point(rect.TopLeft.X + cornerRadius.TopLeft, rect.TopLeft.Y),
new Size(cornerRadius.TopLeft, cornerRadius.TopLeft),
90, false, SweepDirection.Clockwise, isStroked, isSmoothJoin);
context.LineTo(rect.TopRight - new Vector(cornerRadius.TopRight, 0), isStroked, isSmoothJoin);
context.ArcTo(new Point(rect.TopRight.X, rect.TopRight.Y + cornerRadius.TopRight),
new Size(cornerRadius.TopRight, cornerRadius.TopRight),
90, false, SweepDirection.Clockwise, isStroked, isSmoothJoin);
context.LineTo(rect.BottomRight - new Vector(0, cornerRadius.BottomRight), isStroked, isSmoothJoin);
context.ArcTo(new Point(rect.BottomRight.X - cornerRadius.BottomRight, rect.BottomRight.Y),
new Size(cornerRadius.BottomRight, cornerRadius.BottomRight),
90, false, SweepDirection.Clockwise, isStroked, isSmoothJoin);
context.LineTo(rect.BottomLeft + new Vector(cornerRadius.BottomLeft, 0), isStroked, isSmoothJoin);
context.ArcTo(new Point(rect.BottomLeft.X, rect.BottomLeft.Y - cornerRadius.BottomLeft),
new Size(cornerRadius.BottomLeft, cornerRadius.BottomLeft),
90, false, SweepDirection.Clockwise, isStroked, isSmoothJoin);
context.Close();
}
dc.DrawGeometry(brush, pen, geometry);
}
Information from:
http://wpftutorial.net/DrawRoundedRectangle.html
This one will work even with Rectangle (or anything else) inside it:
<Border>
<Border.OpacityMask>
<VisualBrush>
<VisualBrush.Visual>
<Border CornerRadius="5" Height="100" Width="100" Background="White"/>
</VisualBrush.Visual>
</VisualBrush>
</Border.OpacityMask>
// put your rounded content here
</Border>
You will have to play with Height and Width if you do not have exact size of content.

Resources