two questions about rectangle and canvas in silverlight 4 - silverlight

I have a rectangle on canvas. I can already moving this object using with mouse, but I can't find how can I resize it in runtime using mouse too?
And second question, how can I programatically check positions of each objects (e.g rectangles) on the canvas?

Most people use a Thumb. This is an msdn article that shows you how to use a thumb to resize a canvas. The same principles can be applied to your rectangle.

Re-sizing a rectangle using the mouse can be pretty involved. Basically you can listen for mouse-down, mouse-up, and mouse-move events which would allow you to adjust the width and height of it programmatically.
To move a rectangle within the canvas, try the following concept:
double x = Canvas.GetLeft(this.myRectangle);
x += 100;
Canvas.SetLeft(this.myRectangle, x);

Related

Move (zoom and pan) around a large Canvas

I have a lot of images placed on a canvas (~150 pages converted PDF).
I would like to be able to move around from one region to another of this canvas by animating the movement (zoom and pan).
My animation keys are in a listbox. I have a "play" button to play all.
When I click an animation key, my "camera" automatically moves to the defined location.
It's a kind of "Prezi wall".
This is only half or three quarters of an answer really, but hopefully you can fill in the gaps. You could try using the VisualBrush Class. First you set up the visual that the VisualBrush will paint using your full Canvas:
VisualBrush visualBrush = new VisualBrush();
visualBrush.Visual = yourCanvasElement;
You then paint with the Brush onto, let's say, a Rectangle element:
Rectangle rectangle = new Rectangle();
...
rectangle.Fill = visualBrush;
You can then use the VisualBrush.Viewbox property to move the content about. Now I think that there is some way of zooming in and out, but I can't remember at the moment.
Alternatively, you could use the ViewBox class. You can get your zooming effect by changing the size of the content and the ViewBox and get your panning effect by using a ScrollViewer. There's a post on StackOverflow that demonstrates this, so please take a look at the Zooming To Mouse Point With ScrollView and ViewBox in Wpf post for more help with this method.

Panel with percentage coordinates

I would like use a panel whose children have coordinates specified as percentage of total panel's width/height. Moreover, I should be able to animate the coordinate property, for example to make a button move from 10% to 50% panel's width.
I've made 2 attempts:
Use a Grid and specify size as stars - this was not enough, because AFAIK by default WPF cannot animate distance properties specified by stars. I've found somewhere a custom class that enabled me to do so, it even worked, hovewer I consider that solution overly complicated an I am looking for something simpler.
Use a Canvas with fixed width and height and put it inside a Viewbox - this is a simple solution, but when resizing the Viewbox the whole content of Canvas is resized too. I want the content to have fixed size.
Is there a simple solution or should I implement my own panel (or maybe extend one of the existing ones, i.e. Canvas)?
Cheers!
I would:
subclass Canvas, perhaps calling it RelativeCanvas or RatioCanvas
add two attached properties: XRatio and YRatio
override ArrangeOverride and loop over all children. For each child, use their XRatio and YRatio along with the ActualWidth and ActualHeight of the RelativeCanvas to calculate and apply values for their Canvas.Left and Canvas.Top attached properties
You would use it as follows:
<local:RelativeCanvas>
<!-- the top-left of this button will be center of panel -->
<Button local:RelativeCanvas.XRatio="50" local:RelativeCanvas.YRatio="50"/>
</local:RelativeCanvas>
One thing you might like to add after you get that working is control over alignment. For example, I might to align the center of a control to the specified ratio, not its top-left corner.
There's one here: WPF Proportional Panel

WPF Canvas: centered origin, scaled axes (and y inverted), responding to mouse events

In a simple code-only WPF application I'm writing, I would like to have a custom Canvas.
I've found questions similar to this one here in StackOverflow, but couldn't find exactly this one, nor a simple way to adapt another answer to my specific problem (please note that I have not much experience in WPF).
In my canvas, I'd like it to have the following properties:
the point (0, 0) is on the center of the Canvas;
the x-axis points to the right;
the y-axis points to the top;
the point (1, 0) is about 1 inch to the right of the origin; and
in every event, the position of the mouse is given in the coordinate system defined above.
In this answer, Ray Burns propose a very simple solution to my first 3 points. It is trivial to modify that code so that it deals with my point number 4 as well (change 1 and -1 in the RenderTransform to other constants).
However, that very simple and excellent solution for many problems is based on setting width and height to 0, and centering the canvas on its container. Therefore, there's no canvas to capture events like a click, so this solution won't handle my fifth property.
What's the easiest way to achieve this? Inherit from Panel and do everything by hand? Inherit from Canvas, intercept every event and modify the coordinates?
Put Canvas inside a Border. Border has mouse events. Another case is to place Border on the top of the Canvas.

WPF Adorner Transforms

I am building a control, where the user can "draw" resizable rectangles that are laid over the content. To resize those rectangles, I use an Adorner on top of them which contains 4 Thumbs to change the size of the rectangle.
The problem is, that this control is is "zoomable", meaning a ScaleTransform is applied to the whole control depending on a zoom factor. The Thumbs in the Adorner are affected by this ScaleTransform as well.
But I need them to keep their size, independent of the zoom factor.
I tried putting the Adorners in a Layer of another non-transformed control instead of the rectangle-layer, but this didn't work.
How can I achieve this?
Thanks,
Andrej
Have you checked this post: Transformations on AdornedElement are also applied to Adorner?! ? Does it work?
I also find this question on MSDN: How to exclude scaleTransform from GeneralTransform in Adorner GetDesiredTransform method., this is good because also there is some example code.

WPF - how to best implement a panel with draggable/zoomable children?

I'm trying to modify the default graph viewer of the Graph# library because its user interface is awful (just try dragging a node outside of the boundaries, you'll see!)
The basic setup is this: there is a GraphCanvas control (inherited from Panel) which has children of Vertex and Edge control types. What I want to achieve is:
GraphCanvas has scroll bars if the contents do not fit in the screen;
GraphCanvas can also be scrolled by "dragging" it (just click on an empty space and drag);
GraphCanvas can be zoomed in and out (via CTRL+mouse wheel);
Vertices can be dragged around. If a vertex is dragged outside the current boundaries of GraphCanvas, the boundaries are increased. The scroll bars should reflect this, however the current viewport should not scroll away while the vertex is being dragged . The same goes if dragging a vertex reduces the boundaries of GraphCanvas - it should stay the same size until the drag operation is finished and resize only then. Automatically scrolling the viewport during a drag operation is awfully confusing and easily introduces dragging errors. See the original implementation if you want to know what I mean.
Although I've got a fair bit of experience with .NET, I'm still a complete beginner in WPF. My current attempt is (in the measure/arrange layout phase) to give each vertext the XY coordinate it desires (even if negative) and implement zooming/scrolling by handling mouse events on the GraphCanvas and modifying the RenderTransform property. Dragging just changes the XY coordinates on the specific vertex (probably triggering the re-layout of the whole thing which would be nice to avoid too). Scrollbars are implemented by placing the GraphCanvas inside a ScrollViewer and implementing IScrollInfo on the GraphCanvas.
Unfortunately there seems to be a problem: I can get mouse events on the GraphCanvas itself only if it has a background at the point. That would be OK, I want a white background anyway, but in the negative coordinates of the GraphCanvas it does not draw the background - and thus does not respond to mouse events.
I'm also wondering if I'm doing the Right Thing by allowing all my child controls (vertices and edges) to go into negative coordinates. How would you implement this?
Added: To clarify about the background problem check out the following screenshot:
(source: valts.21.lv)
What you see here is a simple Windows Forms form with a WPF Host control on it. That has a ScrollViewer in it, and the ScrollViewer has the GraphCanvas in it. The GraphCanvas contains 4 vertices and 6 edges.
The GraphCanvas is stretched to fill the ScrollViewer. But since some of the vertices are at negative coordinates, it has a RenderTransform applied which simply shifts everything to the right (TranslateTransform). It also has a white background brush.
Note the gray area on the left. That's still a part of the GraphCanvas, but the background brush somehow doesn't exted there. Also, if I left-click there with my mouse (not on a node, but on the gray area), I do NOT get an event. If I left-click on the white area, I get all events just fine.
Call CaptureMouse on canvas.mouseDown and ReleaseMouseCapture on mouse up. Also, if you set your canvas background to transparent it will still be hit testable
You can attach a 'Draggable' behavior to each element.

Resources