Ive done some tranforms for my object in the canvas, like rotating and transforming.
How can i store the new coordinates afterwards? If I try to move the object around it will only use the new Transforms.
From what I can see, this is fairly non-trivial. Generally, you'll want to let WPF handle that kind of thing for you.
That said, here's what I've been able to come up with, based on information from here. Given a text block "textBlockName":
HwndSource hwndSource = PresentationSource.FromVisual(textBlockName) as HwndSource;
Visual root = hwndSource.RootVisual;
// Translate the point from the visual to the root.
GeneralTransform transformToRoot = textBlockName.TransformToVisual(root);
Point p = new Point(0,0);
p = transformToRoot.Transform(p);
p = hwndSource.CompositionTarget.TransformToDevice.Transform(p ) ;
//Display the top left point of the text box, after transforms.
MessageBox.Show(p.ToString() );
Edit: Looking at this further, I cannot find a better solution to this. This seems to handle every situation I can think to throw at it, though.
Related
How do I provide a print option on my silverlight application. I am able to print using the PrintDocument class but it cuts of the edges.
Is there a way to shrink the view to fit in a print paper. Thanks for any help.
I am using the below code:
PrintDocument document = new PrintDocument();
document.PrintPage += (s, args) =>
{
args.PageVisual = this.LayoutRoot;
};
document.Print("Silverlight Print Application Demo");
There are two conceptually different tasks here:
Printing an element as rendered in the ui at some point and
Render an element exclusively for printing.
Since you're complaining about the cutting off of edges, I assume you want to do the latter. For that, I wouldn't add the current control's layout root, which I suspect you're doing. Add something that is not yet added to the visual tree, or remove it from its parent before printing.
If you have to remove it first for some reason (perhaps because the user needs to interact with it first), then store the element in a variable printedPage that you can re-add to the visual tree on the PrintDocument.EndPrint event.
For the main event handler use something like this:
void HandlePrintPage(object sender, PrintPageEventArgs e)
{
var panel = new Grid();
// get an element to print that is not attached to the visual tree
printedPage = GetDetachedPageToPrint();
panel.Children.Add(printedPage.ReportPage);
// we wrap it in a Viewbox to make it full-page
var viewbox = new Viewbox() { Child = panel };
// we need to have a measure pass
viewbox.Measure(e.PrintableArea);
e.PageVisual = viewbox;
// for more pages, we would need to be more careful
//with parent detachments
e.HasMorePages = false;
}
I had the same problem a couple of months ago and tried several solutions.
I`ve already answered this question in another post. Please check out this:
https://stackoverflow.com/a/20896774/1141477
It converts the framework element into images and fit it inside a rectangle, which is from the same size as the printableArea. It worked well to me.
Hope it helps!
I'm writing some WPF code involving Adorners. I'm using Josh Smith's UIElementAdorner.cs (found in the project on his Infragistics Blog). I'm adorning with a blurb of information text. I need to place my adorner smartly, so that it does not clip off the screen.
What's the best way to find out if I'm going to clip?
I'm using the following code to create and place my adorner. I have a funny feeling that basing whether or not I'll clip on the AdornerLayer isn't the best option.
var infoBubble = new InfoBubble {InformationText = #"I like cheese."};
var adornedElementRect = new Rect(Target.DesiredSize);
var layer = AdornerLayer.GetAdornerLayer(Target);
var adorner = new UiElementAdorner<Control>(Target) { Child = infoBubble };
adorner.Measure(new Size(layer.ActualWidth, layer.ActualHeight));
var adornerRect = new Rect(adorner.DesiredSize);
var top = -1*(adornerRect.Height);
var left = adornedElementRect.Width/2;
// Using layer to judge where to place the adorner
var upperLeftPoint = Target.TranslatePoint(new Point(left, top), layer);
var lowerRightPoint = Target.TranslatePoint(new Point(left + adornerRect.Width,
top + adornerRect.Height), layer);
if (upperLeftPoint.Y < 0) top -= upperLeftPoint.Y; // shift down by Y
if (lowerRightPoint.X > layer.ActualWidth)
left -= (lowerRightPoint.X - layer.ActualWidth); // shift left
Keep in mind that this code is contained in a TargetedTriggerAction that designers (aka users of Blend) are expected to use when they want information blurbs above certain UI elements. Thus, this code will know very little about the element to be adorned or its environment.
Yes, is the best answer I can discern.
According to further reading and some experimentation, when calling GetAdornerLayer we receive the lowest layer above the target control in the visual tree. This means we could get a layer below the AdornerDecorator's layer defined in a Window's template. That lower AdornerDecorator could have ClipToBounds="True" (I have no idea why, but it could).
Knowing this information, I can be relatively certain that the AdorneLayer I'm drawing into is the best bounding box for whatever I'm drawing. I could have the ability to draw outside this box (for example if ClipToBounds were False on a AdornerDecorator lower than the Window's), but I shouldn't count on that ability.
I am working on a paint like application in wpf.I want the users to be able to add some drawings over images or plain surfaces.Also i want to draw some basic shapes like line,ellipse or a rectangle.I am trying to work with an inkcanvas,where i can do freehand drawing,but i cant draw shapes like in paint.Can anyone guide me and provide some clues on how to do it.Please help me on this.Any inputs will be greatly appreciated.
There are two sorts of collections in an InkCanvas:
Strokes, which are composed of StylusPoints and defined by DrawingAttributes. That's what the Ink is, as drawn by a mouse or stylus.
The other is Children, which can contain FrameworkElements. Ellipse, for instance, is a Shape is a FrameworkElement.
Try playing around with yourCanvas.Children.Add(ellipse) and see how you go. There is certainly no reason to shy away from the InkCanvas just because you also want to use predefined shapes.
It's worth pointing out, though, that the InkCanvas's little brother, the InkPresenter, does NOT have a Children property. And Silverlight only has that one.
WPF provides a Shape class that includes prebuilt methods that you can draw shapes with. Don't use the inkcanvas and instead draw directly to a canvas.
Here http://ciintelligence.blogspot.com/2011/07/silverlight-drawing-tool-silver-draw.html
you can find better control which improved SilverDraw control with extra features:
Freatures are:
* You can draw basic shapes and also can draw using freehand pencil.
* You can erase drawing.
* You can undo and redo drawing.
* Can save drawing as jpeg in server side.
Here is a simple implementation:
public void drawCircleAp(Double EHeight, Double EWidth, InkCanvas surface)
{
Ellipse e1 = new Ellipse();
e1.Width = EWidth;
e1.Height = EHeight;
var brush = new SolidColorBrush();
brush.Color = Color.FromArgb(100, 0, 0, 0);
e1.Stroke = brush;
e1.StrokeThickness = 4;
surface.Children.Add(e1);
}
I am new to Silverlight. Just created my first application that shows deepzoom images.
Looking for some pointers how to display vector graphics in Silverligth. The graphics are all in 2D and is a series of lines (x1y1, x2y2), points (xy), basic shapes. The data is available in ASCII text files.
What is the way(s) to read the data from files and draw in SL? Do I need to convert / translate the vector objects into images (XAML) first? Where to start?
The ideal case is that all vector obects should be selectable either programmatically or by user actions.
Thanks,
Val
There is no direct drawing API to my knoweldge, but you can add the values seperately by adding various shapes to the visual tree.
The code you are looking for will likely involve the Path class and, in turn, PathFigure and PolyLineSegment (or possibly LineSegment).
Below is some code that draws a square:
PolyLineSegment segment = new PolyLineSegment();
segment.Points.Add(new Point(0, 50));
segment.Points.Add(new Point(50, 50));
segment.Points.Add(new Point(50, 0));
segment.Points.Add(new Point(0, 0));
PathFigure figure = new PathFigure()
{
StartPoint = new Point(0, 0)
};
figure.Segments.Add(segment);
PathGeometry geometry = new PathGeometry()
{
Figures.Add(pathFigure)
};
Path path = new Path()
{
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 2,
Data = pathGeometry
};
// To render, the Path needs to be added to the visual tree
LayoutRoot.Children.Add(path);
Edit If the data in the ASCII text files cannot change at runtime, it might be worth investigating writing a script that transforms the files into XAML so it can be compiled.
First of you have the issue of actually getting access to the files.
Getting the file content
If you have these files held somewhere serverside then you would use WebClient to fetch the file using DownloadStringAsync.
On the other hand if the user is to open a file locally then you need use the OpenFileDialog class to ask them to open the file and then use OpenText on the FileInfo object that OpenFileDialog provides to read the string data.
Parsing
Well its your format so you'll have to code that yourself.
__Generating UI elements_
You will not have to convert it to Xaml. Since you want these vector items to be individually selectable elements then you probably want to use the set of Shape types found in the System.Windows.Shapes namely, Elipse, Line, Path, Polygon, Polyline and Rectangle.
No doubt the format in question has someway to define the position of these elements relative to a fixed 0,0 point. Hence the best panel to use to display these is a Canvas.
You would read through each Vectored item, select create an instance of one of the appropriate shapes set its properties based on the data in the item. You would need to determine its correct location within a Canvas and use the Canvas.Left and Canvas.Top attached properties. The add the shape to the Children collection of the Canvas.
We use Windows Forms and custom user controls, and I would like to be able to rotate the panel hosting the userControl in a particular form. I have seen similar functionnalities with WPF, but I can't use it for the moment. Is it possible to achieve the rotation of a panel and its children using possibly built-in .NET methods or GDI+?
I have seen some pretty cool visual effect with menus that are displayed in game development, so I was wondering if it would be possible to create similar effects using Windows Forms.
Rotating a panel and its children in Windows Forms is not something directly supported, and I think it will end up being a buggy headache that could easily suck up lots of time. It's especially painful to think about when you could do this in WPF with zero lines of C# code and only a tiny bit of XAML.
You can use rotations in GDI+ by calling the RotateTransform method on a Graphics object.
However, rotating an entire control is not so simple, and will depend heavily on how the control is implemented.
If it's a composite UserControl that has other controls inside of it, you're out of luck.
If it's a sinlge control that paints itself, try inheriting the control, overriding the OnPaint method, and calling RotateTransform on the Graphics object. However, you will probably have trouble with it. In particular, you will probably need to override all of the mouse events and call the base control's events with rotated coordinates.
You can get halfway there by calling the DrawToBitmap method on your panel, then rotating the bitmap and displaying it e.g. in a PictureBox:
var bitmap = new Bitmap(panel.Width, panel.Height);
panel.DrawToBitmap(bitmap, new Rectangle(Point.Empty, panel.Size));
bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
var pictureBox = new PictureBox();
pictureBox.Location = panel.Location;
pictureBox.SizeMode = PictureBoxSizeMode.AutoSize;
pictureBox.Image = bitmap;
Controls.Remove(panel);
Controls.Add(pictureBox);
Rotation angles other than 90-degree increments are also possible, if you draw the bitmap into another bitmap using GDI:
var bitmap2 = new Bitmap(bmp.Width + 75, bmp.Height + 100);
var graphics = Graphics.FromImage(bmp2);
graphics.TranslateTransform(bitmap2.Width / 2, bitmap2.Height / 2);
graphics.RotateTransform(-15f);
graphics.TranslateTransform(-bitmap.Width / 2, -bitmap.Height / 2);
graphics.DrawImageUnscaled(bitmap, Point.Empty);
graphics.Dispose();
The problem of course is that you're only displaying an image of your panel, and not the panel itself, so it's no longer possible to interact with the controls inside.
That could probably be done as well, but you would have to mess with window messages, which gets quite a bit more complicated. Depending on your needs you might also be able to get away with handling click and key events on the PictureBox, manipulating the controls in the panel, and then updating the image.