WriteableBitmap shapes rendering - silverlight

I am trying to render some Shape objects(Line, Rectangle) in Silverlight and I am using WriteableBitmap.Render(myShape, transform). The problem is that Render function seems to be missing antialiasing. Am I missing something or this is not possible using WriteableBitmap?
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
bmp = new WriteableBitmap(800, 600);
testImage.Source = bmp;
line = new Line() { X1 = 10, X2 = 500, Y1 = 10, Y2 = 300 };
line.Stroke = new SolidColorBrush(Colors.Red);
line.StrokeStartLineCap = PenLineCap.Round;
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;
line.StrokeThickness = 1;
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
bmp.Render(line, line.GeometryTransform);
bmp.Invalidate();
}

Related

Draw line on run time WPF

I want to draw line on run time using mouse.I have tried in below way
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement f = e.Source as FrameworkElement;
FrameworkElement pr = f.Parent as FrameworkElement;
Rect feRect = f.TransformToAncestor(pr).TransformBounds(
new Rect(0.0, 0.0, f.ActualWidth, f.ActualHeight));
Image image = sender as Image;
Point textLocation = e.GetPosition(image);
textLocation.Offset(-4, -4);
var Top = feRect.Height - textLocation.Y;
var Bottom = textLocation.Y - 1;
var Left = textLocation.X - 1;
var Right = feRect.Width-textLocation.X;
// Create an annotation where the mouse cursor is located.and add control using adorner layer
_currentAnnotations = ImageAnnotation.Create(
image,
textLocation,
feRect
);
}
private void Image_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Image image = sender as Image;
EndPosition = e.MouseDevice.GetPosition(image);
// Draw next line and...
l.X1 = StartPosition.X;
l.X2 = EndPosition.X;
l.Y1 = StartPosition.Y;
l.Y2 = EndPosition.Y;
l.Stroke = Brushes.Red;
l.StrokeThickness = 5;
StartPosition = EndPosition;
}
if(_currentAnnotations!=null && l!=null)
_currentAnnotations.Lines = l;
}
But it doesn't give the result as expected. the line that am getting is different from the mouse location. my output should be like a pen tool. 1.what's wrong with my way?
2. Is inkCanvas the only way to draw line in wpf?if yes why so?
3.
1.what's wrong with my way?
You could try to set the StartPosition property in the Image_MouseLeftButtonDown event handler:
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement f = e.Source as FrameworkElement;
FrameworkElement pr = f.Parent as FrameworkElement;
Rect feRect = f.TransformToAncestor(pr).TransformBounds(
new Rect(0.0, 0.0, f.ActualWidth, f.ActualHeight));
Image image = sender as Image;
...
StartPosition = e.MouseDevice.GetPosition(image);
}
InkCanvas is the only built-in WPF control that receives and displays ink strokes. But you could for example add lines to a Canvas or perform any other kind of custom drawing action yourself.
Here is a basic sample that should give you the idea.
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent();
}
Point EndPosition;
Point StartPosition;
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
FrameworkElement fe = sender as FrameworkElement;
EndPosition = e.MouseDevice.GetPosition(fe);
Line l = new Line();
l.X1 = StartPosition.X;
l.X2 = EndPosition.X;
l.Y1 = StartPosition.Y;
l.Y2 = EndPosition.Y;
l.Stroke = Brushes.Red;
l.StrokeThickness = 5;
StartPosition = EndPosition;
canvas.Children.Add(l);
}
}
private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement fe = sender as FrameworkElement;
StartPosition = e.MouseDevice.GetPosition(fe);
}
}
<Canvas x:Name="canvas" Width="500" Height="500" Background="Yellow"
MouseLeftButtonDown="canvas_MouseLeftButtonDown" MouseMove="canvas_MouseMove" />

How can I draw lines in WPF inkCanvas with sequence of PNGs

I was trying to make a method to draw some arrowheads from a PNG image with transparency.
While I moving mouse, the application will be plot that png along the path.
What is the way to make that?
Another form I was wondering is creating a polygnon shape. I was tryed draw the shape (triangle) when enter on mouse down event.
void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
double posX = e.GetPosition(null).X;
double posY = e.GetPosition(null).Y;
double posX1 = posX - (posX / 4);
double posY1 = posY - (posY / 4);
double posX2 = posX + (posX / 4);
double posY2 = posY;
double posX3 = posX - (posX / 4);
double posY3 = posY + (posY - posY / 3);
Polygon p = new Polygon();
p.Stroke = Brushes.Black;
p.Fill = Brushes.LightBlue;
p.StrokeThickness = 1;
p.HorizontalAlignment = HorizontalAlignment.Left;
p.VerticalAlignment = VerticalAlignment.Center;
p.Points = new PointCollection() { new Point(posX1, posY1), new Point(posX2, posY2), new Point(posX3, posY3), new Point(posX1, posY1) };
MyCanvas.Children.Add(p);
}
But still can't click and draw a triangle correctly in mouse (x,y) position.
http://i.stack.imgur.com/bM2i4.png
Here is a quick example.
XAML
<Canvas x:Name='DrawingCanvas'
Margin='30'
Background='LightBlue'
MouseDown='Canvas_MouseDown'
MouseMove='Canvas_MouseMove'
MouseUp='Canvas_MouseUp'>
<Rectangle>
<Rectangle.Fill>
<ImageBrush ImageSource='Arrow.png' x:Name='ArrowBrush'/>
</Rectangle.Fill>
</Rectangle>
</Canvas>
CODE
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private bool _isDrawing = false;
private Point _lastPosition;
const double MIN_MOVEMENT = 60;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e) {
_isDrawing = true;
_lastPosition = e.GetPosition(DrawingCanvas);
// add the first arrow
AddArrow(_lastPosition);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e) {
if (!_isDrawing)
{
return;
}
var currentPosition = e.GetPosition(DrawingCanvas);
// draw a new image if mouse has traveled minimum distance
if (Math.Abs((currentPosition.X - _lastPosition.X)) > MIN_MOVEMENT ||
Math.Abs((currentPosition.Y - _lastPosition.Y)) > MIN_MOVEMENT)
{
AddArrow(currentPosition);
_lastPosition = e.GetPosition(DrawingCanvas);
}
}
private void AddArrow(Point currentPosition) {
var rect = new Rectangle();
rect.Width = 120;
rect.Height = 120;
rect.Fill = ArrowBrush;
Canvas.SetTop(rect, currentPosition.Y);
Canvas.SetLeft(rect, currentPosition.X);
DrawingCanvas.Children.Add(rect);
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e) {
_isDrawing = true;
}
}
Screenshot

Simulating a Drag/Drop event in WPF

I want to simulate a drag/drop event in WPF.
For this I'll need to gain access to the data stored in the "Drag/Drop buffer" and also I'll need to create a DragEventArgs.
I noticed that the DragEventArgs is sealed and has no public ctor.
So my questions are:
1. how can I create an instance of DragEventArgs?
2. How can I gain access to the drag/drop buffer?
i recently do this! i simulated drag/drop with MouseDown, MouseMove and MouseUp events. for example for my application, i have some canvases that i want to drag and drop them. every canvas has an id. in MouseDown event, i buffer its id and use it in MouseMove and MouseUp event. Desktop_Canvas is my main Canvas that contains some canvases. these canvases are in my dictionary (dic).
here is my code:
private Dictionary<int, Win> dic = new Dictionary<int, Win>();
private Point downPoint_Drag = new Point(-1, -1);
private int id_Drag = -1;
private bool flag_Drag = false;
public class Win
{
public Canvas canvas = new Canvas();
public Point downpoint = new Point();
public Win()
{
canvas.Background = new SolidColorBrush(Colors.Gray);
}
}
private void Desktop_Canvas_MouseMove(object sender, MouseEventArgs e)
{
try
{
Point movePoint = e.GetPosition(Desktop_Canvas);
if (flag_Drag && downPoint_Drag != new Point(-1, -1))
{
double dy1 = movePoint.Y - downPoint_Drag.Y, x = -1, dx1 = movePoint.X - downPoint_Drag.X, y = -1;
downPoint_Drag = movePoint;
if (x == -1)
x = Canvas.GetLeft(dic[id_Drag].canvas) + dx1;
if (y == -1)
y = Canvas.GetTop(dic[id_Drag].canvas) + dy1;
Canvas.SetLeft(dic[id_Drag].canvas, x);
Canvas.SetTop(dic[id_Drag].canvas, y);
}
}
catch
{
MouseEventArgs ee = new MouseEventArgs((MouseDevice)e.Device, 10);
Desktop_Canvas_MouseLeave(null, ee);
}
}
private void Desktop_Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
try
{
downPoint_Drag = new Point(-1, -1);
id_Drag =-1;
flag_Drag = false;
}
catch
{
MouseEventArgs ee = new MouseEventArgs((MouseDevice)e.Device, 10);
Desktop_Canvas_MouseLeave(null, ee);
}
}
private void Desktop_Canvas_MouseLeave(object sender, MouseEventArgs e)
{
MouseButtonEventArgs ee = new MouseButtonEventArgs((MouseDevice)e.Device, 10, MouseButton.Left);
Desktop_Canvas_MouseLeftButtonUp(null, ee);
}
void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
downPoint_Drag = e.GetPosition(Desktop_Canvas);
int hoverId = HoverWin(downPoint_Drag);
flag_Drag = true;
id_Drag = hoverId;
dic[id_Drag].downpoint = new Point(downPoint_Drag.X, downPoint_Drag.Y);
}
private int HoverWin(Point p)
{
foreach (int i in dic.Keys)
{
if (dic[i].canvas.IsMouseOver)
return i;
}
return -1;
}

WPF: Storyboard loop object owned by another thread

Hi all my simple code looks like this
private void flipForeverever(object sender, EventArgs args)
{
moveYs = new DoubleAnimation();
m2oveYs = new DoubleAnimation();
try
{
sf.Remove(this);
sf.Children.Clear();
}
catch (Exception e)
{
}
if (firstPanelAngle == 360)
{
moveYs.To = 180;
moveYs.From = 0;
}
else
{
moveYs.To = 360;
moveYs.From = 180;
}
if (secondPanelAngle == 360)
{
m2oveYs.To = 180;
m2oveYs.From = 0;
}
else
{
m2oveYs.To = 360;
m2oveYs.From = 180;
}
sf = (Storyboard)FindResource("Storyboard1");
Storyboard.SetTargetName(moveYs, "rotatePanel");
Storyboard.SetTargetProperty(moveYs, new thisPropertyPath(AxisAngleRotation3D.AngleProperty));
Storyboard.SetTargetName(m2oveYs, "rotateSecond");
Storyboard.SetTargetProperty(m2oveYs, new PropertyPath(AxisAngleRotation3D.AngleProperty));
sf.Children.Add(moveYs);
sf.Children.Add(m2oveYs);
// sf.RepeatBehavior = RepeatBehavior.Forever;
if (flipForever)
{
sf.Completed += new EventHandler(delaythespin);
sf.Begin(this);
}
}
private void delaythespin(object sender, EventArgs args)
{
sf.Stop(this);
System.Timers.Timer timer = new System.Timers.Timer(500);
timer.Elapsed += new System.Timers.ElapsedEventHandler(flipForeverever);
timer.Enabled = true;
firstPanelAngle = rotatePanel.Angle;
secondPanelAngle = rotateSecond.Angle;
timer.Start();
}
So basically i call flipForeverever through a click call and it is supposed to loop forever until i set flipforever to false... But then it is giving me this error...
The calling thread cannot access this object because a different thread owns it.
Any help will really be appreciated
It sounds like you might be having thread affinity problems. Have you tried using a DispatcherTimer instead of a System.Timers.Timer?
private DispatcherTimer _timer;
private void GoButton_Click(object sender, RoutedEventArgs e)
{
_timer = new DispatcherTimer(); // create timer
_timer.Interval = new TimeSpan(0, 0, 1); // tick every 1s
_timer.Tick += new EventHandler(_timer_Tick); // method to call
_timer.Start(); // start timer
}
void _timer_Tick(object sender, EventArgs e)
{
// we should be on the correct thread now
GoButton.Background = Brushes.Aqua;
}
Or, if you need to use System.Timers.Timer, use Invoke or BeginInvoke to get on the correct thread after the timer fires?
private System.Timers.Timer _timer;
private void GoButton_Click(object sender, RoutedEventArgs e)
{
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Start();
}
void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// use Dispatcher.Invoke on the UI object that you want to modify
// to get on the correct thread for that UI object
GoButton.Dispatcher.Invoke((ThreadStart)(() =>
{
GoButton.Background = Brushes.Aqua;
}));
}

Polygon Mouse Left Button Down Not Firing and Polygon child possible or not?

I have a polygon which has a MouseLeftButtonDown event. When I click near its edges (say 10 pixes inside from the borders) the event is not called. What could be the problem of this?
Secondly, can we add child of a polygon?
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Polygon p = new Polygon() {
Stroke = Brushes.Black,
StrokeThickness = 2,
Points = new PointCollection() {new Point(10,10), new Point(50,10),
new Point(56, 45) }};
p.MouseLeftButtonDown += new MouseButtonEventHandler(p_MouseLeftButtonDown);
mygrd.Children.Add(p);
}
void p_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Entered");
}
give the polygon a fill brush and your mouse event fires
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Polygon p = new Polygon() {
Stroke = Brushes.Black,
StrokeThickness = 2,
Fill = Brushes.Transparent, // or something else
Points = new PointCollection() {new Point(10,10), new Point(50,10), new Point(56, 45) }};
p.MouseLeftButtonDown += new MouseButtonEventHandler(p_MouseLeftButtonDown);
mygrd.Children.Add(p);
}

Resources